一、二叉堆
堆有序:
一颗二叉树中每个节点都大于或者等于其两个孩子时,就称为堆有序。
根节点是堆有序的二叉树的最大节点。
堆有序的二叉树可以用指针来表示,
堆有序的完全二叉树除了可以用指针表示外,还可以用数组表示。
二叉堆:
二叉堆是一组堆有序的完全二叉树,并且在数组中按层级存储(不使用数组中0号位置的元素)。
二叉堆可以方便的实现优先队列的各种操作。
对于给定堆中任意的位置k
其父亲的位置:K/2
其两个孩子的位置:2k或者2k+1
这样就可以不使用指针来实现向上查找和向下查找。
二、二叉堆实现
1 package agheap; 2 3 import java.util.ArrayList; 4 5 class Node{ 6 public final int value; 7 Node(int value){ 8 this.value = value; 9 } 10 public String toString(){ 11 return "value:"+value; 12 } 13 } 14 public class BinHeap { 15 private static void swap(ArrayList<Node> aryList,int indexA,int indexB){ 16 Node tmp; 17 tmp = aryList.get(indexA); 18 aryList.set(indexA, aryList.get(indexB)); 19 aryList.set(indexB, tmp); 20 } 21 22 //上浮堆有序化 23 private static void swim(ArrayList<Node> aryList,int index) { 24 while(index > 1 && aryList.get(index).value > aryList.get(index/2).value){//当前元素非堆顶且大于其父亲,需要上浮调整 25 swap(aryList, index, index/2); 26 index = index/2; 27 } 28 } 29 30 //下沉堆有序化 31 private static void sink(ArrayList<Node> aryList,int index,int high){ 32 int indexOfMaxChild; 33 while(true){ 34 if (2*index > high) {break;}//ary[2*index]无孩子 35 if (2*index == high) {//ary[2*index]有左孩子,此时indexOfMaxChild无选择 36 indexOfMaxChild = 2*index; 37 }else {//ary[2*index]有左右两孩子,此时indexOfMaxChild有选择 38 indexOfMaxChild = aryList.get(2*index).value > aryList.get(2*index+1).value?2*index:2*index+1; 39 } 40 if (aryList.get(index).value <aryList.get(indexOfMaxChild).value) {//当前ary[index]不满足局部堆有序 41 swap(aryList, index, indexOfMaxChild); 42 } 43 index = indexOfMaxChild;//继续向下迭代 44 } 45 } 46 47 //sink()构造大根堆 48 public static void createHeap(ArrayList<Node> aryList){ 49 int high = aryList.size()-1; 50 for (int i = high/2; i > 0; i--) {//从非叶节点开始构造,同时sink()保持堆有序 51 sink(aryList, i, high); 52 } 53 } 54 55 // //swim()构造大根堆 56 // public static void createHeap(ArrayList<Node> aryList){ 57 // int high = aryList.size()-1; 58 // for (int i = 1; i <= high; i++) {//从索引1位置开始逐个加入,同时swim()保持堆有序 59 // swim(aryList, i); 60 // } 61 // } 62 public static void insert(ArrayList<Node> aryList,Node target){ 63 aryList.add(target); 64 swim(aryList, aryList.size()-1); 65 } 66 //删除堆顶元素 67 public static Node deleteMax(ArrayList<Node> aryList){ 68 int high = aryList.size()-1; 69 Node node = null; 70 if (high > 0) { 71 swap(aryList, 1, high);//将末尾元素和堆顶元素交换 72 node = aryList.remove(high);//删除末尾元素 73 sink(aryList, 1, high-1);//对堆顶元素重新,使其重新堆有序 74 } 75 return node; 76 } 77 public static void main(String[] args) { 78 // TODO Auto-generated method stub 79 try { 80 int[] ary = {0,12,9,78,10,30,8,20,12,15}; 81 ArrayList<Node> aryList = new ArrayList<Node>(); 82 for (int i = 0; i < ary.length; i++) { 83 aryList.add(new Node(ary[i])); 84 } 85 createHeap(aryList); 86 insert(aryList, new Node(5)); 87 // for(Node node:aryList){ 88 // System.out.println(node); 89 // } 90 int size = aryList.size()-1; 91 for (int i = 0; i < size; i++) { 92 System.out.println(deleteMax(aryList)); 93 } 94 } catch (Exception e) { 95 // TODO: handle exception 96 e.printStackTrace(); 97 } 98 } 99 100 }
三、借助二叉堆实现堆排序
1 private static void createHeap(int[] ary,int index,int high){ 2 int indexOfMaxChild; 3 while(true){ 4 if (2*index > high) {break;}//ary[2*index]无孩子 5 if (2*index == high) {//ary[2*index]有左孩子,此时indexOfMaxChild无选择 6 indexOfMaxChild = 2*index; 7 }else {//ary[2*index]有左右两孩子,此时indexOfMaxChild有选择 8 indexOfMaxChild = ary[2*index] > ary[2*index+1]?2*index:2*index+1; 9 } 10 if (ary[index] < ary[indexOfMaxChild]) {//当前ary[index]不满足局部堆有序 11 swap(ary, index, indexOfMaxChild); 12 } 13 index = indexOfMaxChild;//继续向下迭代 14 } 15 } 16 public static void heapSort(int[] ary){ 17 int high = ary.length-1; 18 for (int i = high/2; i > 0; i--) {//从最大的非叶节点开始构造堆,堆顶位置为1,舍弃数组的0位 19 createHeap(ary, i, high); 20 } 21 while(high > 0){ 22 swap(ary, 1, high);//将大根堆的堆顶元素(最大值)与数组尾部值交换。 23 high--;//大根堆的范围缩小一个单位。 24 createHeap(ary, 1, high);//重构大根堆。 25 26 } 27 }