方案一、只考虑int类型的排序,最简单的实现如下。
1 public class Heap { 2 3 public int heap_size;//在build_max_heap中初始化,由heap_sort自动调用 4 5 public int parent(int i){ 6 return (i - 1) / 2; 7 } 8 public int left(int i){ 9 return 2 * i + 1; 10 } 11 public int right(int i){ 12 return 2 * i + 2; 13 } 14 15 /** 保持堆的性质, 16 * 假定left(i), right(i)为根的两根二叉树都是最大堆, 17 * A[i]可能小于其子女,这样就违背了最大堆性质 18 * 该函数让A[i]在最大堆中“下降”,使以i为根的子树成为最大堆 19 * */ 20 public void max_heapify(int[] A, int i){ 21 int l = left(i); 22 int r = right(i); 23 int largest; 24 // 从A[i] A[left(i)] A[right(i)] 中找出最大,下标存在largest中 25 // 若A[i]为最大,则根据假设,i为根的子树已是最大堆,函数结束 26 // 否则交换A[i]和A[largest],交换后下标为largest的节点值为A[i] 27 // 该节点的子树可能违反最大堆,因此对largest下标递归调用 28 if(l < heap_size && A[l] > A[i]){ 29 largest = l; 30 } 31 else{ 32 largest = i; 33 } 34 if(r < heap_size && A[r] > A[largest]){ 35 largest = r; 36 } 37 if(largest != i){ 38 int tmp = A[i]; 39 A[i] = A[largest]; 40 A[largest] = tmp; 41 42 max_heapify(A, largest); 43 } 44 } 45 46 /** 47 * 建堆 48 * 自底向上将数组A[1..n](此处n=length[A])变成最大堆 49 * 子数组A[(floor(n / 2) + 1) .. n]中的元素都是树中的叶子 50 * 所以对每一个非叶子节点都调用一次该过程 51 * */ 52 public void build_max_heap(int[] A){ 53 heap_size = A.length; // 初始化heap_size 54 for(int i = (heap_size/2 - 1); i > -1; --i){ 55 max_heapify(A, i); 56 } 57 } 58 59 /** 60 * 堆排序算法 61 * 先建造最大堆,根A[1]即为最大,则置换到数组的正确位置A[n] 62 * 从堆中去掉节点n,A[1..n-1]建成最大堆,但新根可能违背了最大堆性质, 63 * 此时调用max_heapify(A,1)可以保持该性质,在A[1..n-1]构造出最大堆。 64 * 不断重复,堆大小从n-1降到2 65 * */ 66 public void heapsort(int[] A){ 67 build_max_heap(A); 68 for(int i = A.length-1; i > 0; --i){ 69 int tmp = A[0]; 70 A[0] = A[i]; 71 A[i] = tmp; 72 --heap_size; 73 max_heapify(A, 0); 74 } 75 } 76 77 public static void show_array(int[] A){ 78 for(int i = 0; i < A.length; ++i){ 79 System.out.print(A[i] + ". "); 80 } 81 System.out.println(); 82 } 83 84 public static void main(String[] args){ 85 int[] A = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; 86
87 88 System.out.println("before heapsort:"); 89 show_array(A); 90 91 Heap h = new Heap(); 92 h.heapsort(A); 93 94 System.out.println("after heapsort:"); 95 show_array(A); 96 97 } 98 99 }
运行结果:
方案二、考虑泛型,使用泛型数组的实现如下:
1 public class HeapTwo<T extends Comparable<T>> { 2 3 T[] A; 4 int heap_size;//在build_max_heap中初始化,由heap_sort自动调用,或在类实例化时构造 5 6 public HeapTwo(T[] A){ 7 this.A = A; 8 this.heap_size = A.length; 9 } 10 11 public int parent(int i){ 12 return (i - 1) / 2; 13 } 14 public int left(int i){ 15 return 2 * i + 1; 16 } 17 public int right(int i){ 18 return 2 * i + 2; 19 } 20 21 /** 保持堆的性质, 22 * 假定left(i), right(i)为根的两根二叉树都是最大堆, 23 * A[i]可能小于其子女,这样就违背了最大堆性质 24 * 该函数让A[i]在最大堆中“下降”,使以i为根的子树成为最大堆 25 * */ 26 public void max_heapify(int i){ 27 int l = left(i); 28 int r = right(i); 29 int largest; 30 // 从A[i] A[left(i)] A[right(i)] 中找出最大,下标存在largest中 31 // 若A[i]为最大,则根据假设,i为根的子树已是最大堆,函数结束 32 // 否则交换A[i]和A[largest],交换后下标为largest的节点值为A[i] 33 // 该节点的子树可能违反最大堆,因此对largest下标递归调用 34 if(l < heap_size && A[l].compareTo(A[i]) > 0 ){ 35 largest = l; 36 } 37 else{ 38 largest = i; 39 } 40 if(r < heap_size && A[r].compareTo(A[largest]) > 0){ 41 largest = r; 42 } 43 if(largest != i){ 44 T tmp = A[i]; 45 A[i] = A[largest]; 46 A[largest] = tmp; 47 48 max_heapify(largest); 49 } 50 } 51 52 /** 53 * 建堆 54 * 自底向上将数组A[1..n](此处n=length[A])变成最大堆 55 * 子数组A[(floor(n / 2) + 1) .. n]中的元素都是树中的叶子 56 * 所以对每一个非叶子节点都调用一次该过程 57 * */ 58 public void build_max_heap(){ 59 heap_size = A.length; // 初始化heap_size 60 for(int i = (heap_size/2 - 1); i > -1; --i){ 61 max_heapify(i); 62 } 63 } 64 65 /** 66 * 堆排序算法 67 * 先建造最大堆,根A[1]即为最大,则置换到数组的正确位置A[n] 68 * 从堆中去掉节点n,A[1..n-1]建成最大堆,但新根可能违背了最大堆性质, 69 * 此时调用max_heapify(A,1)可以保持该性质,在A[1..n-1]构造出最大堆。 70 * 不断重复,堆大小从n-1降到2 71 * */ 72 public void heapsort(){ 73 build_max_heap(); 74 for(int i = A.length-1; i > 0; --i){ 75 T tmp = A[0]; 76 A[0] = A[i]; 77 A[i] = tmp; 78 --heap_size; 79 max_heapify(0); 80 } 81 } 82 83 public void show_array(){ 84 for(int i = 0; i < A.length; ++i){ 85 System.out.print(A[i] + ". "); 86 } 87 System.out.println(); 88 } 89 90 public static void main(String[] args){ 91 Double[] A = {4.3, 1.2, 3.2, 2.8, 16.5, 9.3, 10.6, 14.6, 8.4, 7.0}; 92 93 System.out.println("before heapsort:"); 94 95 96 HeapTwo h = new HeapTwo(A); 97 h.show_array(); 98 h.heapsort(); 99 100 System.out.println("after heapsort:"); 101 h.show_array(); 102 103 } 104 }
最大优先级队列:
1 package org.hhj; 2 3 public class Heap { 4 5 int[] A; 6 int heap_size;//在build_max_heap中初始化,由heap_sort自动调用,或在类实例化时构造 7 8 public Heap(int[] A){ 9 this.A = A; 10 this.heap_size = A.length; 11 } 12 13 public int parent(int i){ 14 return (i - 1) / 2; 15 } 16 public int left(int i){ 17 return 2 * i + 1; 18 } 19 public int right(int i){ 20 return 2 * i + 2; 21 } 22 23 /** 保持堆的性质, 24 * 假定left(i), right(i)为根的两根二叉树都是最大堆, 25 * A[i]可能小于其子女,这样就违背了最大堆性质 26 * 该函数让A[i]在最大堆中“下降”,使以i为根的子树成为最大堆 27 * */ 28 public void max_heapify(int[] A, int i){ 29 int l = left(i); 30 int r = right(i); 31 int largest; 32 // 从A[i] A[left(i)] A[right(i)] 中找出最大,下标存在largest中 33 // 若A[i]为最大,则根据假设,i为根的子树已是最大堆,函数结束 34 // 否则交换A[i]和A[largest],交换后下标为largest的节点值为A[i] 35 // 该节点的子树可能违反最大堆,因此对largest下标递归调用 36 if(l < heap_size && A[l] > A[i]){ 37 largest = l; 38 } 39 else{ 40 largest = i; 41 } 42 if(r < heap_size && A[r] > A[largest]){ 43 largest = r; 44 } 45 if(largest != i){ 46 int tmp = A[i]; 47 A[i] = A[largest]; 48 A[largest] = tmp; 49 50 max_heapify(A, largest); 51 } 52 } 53 54 /** 55 * 建堆 56 * 自底向上将数组A[1..n](此处n=length[A])变成最大堆 57 * 子数组A[(floor(n / 2) + 1) .. n]中的元素都是树中的叶子 58 * 所以对每一个非叶子节点都调用一次该过程 59 * */ 60 public void build_max_heap(int[] A){ 61 heap_size = A.length; // 初始化heap_size 62 for(int i = (heap_size/2 - 1); i > -1; --i){ 63 max_heapify(A, i); 64 } 65 } 66 67 /** 68 * 堆排序算法 69 * 先建造最大堆,根A[1]即为最大,则置换到数组的正确位置A[n] 70 * 从堆中去掉节点n,A[1..n-1]建成最大堆,但新根可能违背了最大堆性质, 71 * 此时调用max_heapify(A,1)可以保持该性质,在A[1..n-1]构造出最大堆。 72 * 不断重复,堆大小从n-1降到2 73 * */ 74 public void heapsort(int[] A){ 75 build_max_heap(A); 76 for(int i = A.length-1; i > 0; --i){ 77 int tmp = A[0]; 78 A[0] = A[i]; 79 A[i] = tmp; 80 --heap_size; 81 max_heapify(A, 0); 82 } 83 } 84 85 public static void show_array(int[] A){ 86 for(int i = 0; i < A.length; ++i){ 87 System.out.print(A[i] + ". "); 88 } 89 System.out.println(); 90 } 91 92 /** 93 * 返回A[]中具有最大关键字的元素 94 * @param A 95 * @return 96 */ 97 public int heap_maximum(int[] A){ 98 return A[0]; 99 } 100 101 /** 102 * 去掉并返回A中的具有最大关键字的元素 103 * @param A 104 * @return 105 */ 106 public int heap_extract_max(int[] A){ 107 if(heap_size < 1){ 108 System.out.println("heap underflow"); 109 return -1; 110 } 111 int max = A[0]; 112 A[0] = A[heap_size - 1]; 113 --heap_size; 114 max_heapify(A, 0); 115 return max; 116 } 117 118 /** 119 * 将元素i的关键字的值增加到key,这里key值不可小于i的原关键字的值 120 * @param A 121 * @param i 122 * @param key 123 */ 124 public void heap_increase_key(int[] A, int i, int key){ 125 if(key < A[i]){ 126 System.out.println("new key is smaller than current key"); 127 } 128 A[i] = key; 129 while(i > 1 && A[parent(i)] < A[i]){ 130 int tmp = A[i]; 131 A[i] = A[parent(i)]; 132 A[parent(i)] = tmp; 133 i = parent(i); 134 } 135 } 136 137 /** 138 * 将key插入到最大堆A中,先用一个关键字值为负无穷的叶节点扩展对大队, 139 * 然后调用heap_increase_key来设置新节点的关键字的正确值,并保持最大堆性质。 140 * @param A 141 * @param key 142 */ 143 public void max_heap_insert(int[] A, int key){ 144 ++heap_size; 145 A[heap_size] = Integer.MIN_VALUE; 146 heap_increase_key(A, heap_size, key); 147 148 } 149 public static void main(String[] args){ 150 151 152 } 153 154 }