堆排序
堆积排序(Heapsort)是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O(nlog2n) ,堆排序的堆序的平均性能较接近于最坏性能。
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
(2)大根堆排序算法的基本操作:
① 初始化操作:将R[1..n]构造为初始堆;
② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
注意:
①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。
1 public class HeapSortTest { 2 3 public static void main(String[] args) { 4 int[] data5 = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 }; 5 print(data5); 6 heapSort(data5); 7 System.out.println("排序后的数组:"); 8 print(data5); 9 } 10 11 public static void swap(int[] data, int i, int j) { 12 if (i == j) { 13 return; 14 } 15 data[i] = data[i] + data[j]; 16 data[j] = data[i] - data[j]; 17 data[i] = data[i] - data[j]; 18 } 19 20 public static void heapSort(int[] data) { 21 for (int i = 0; i < data.length; i++) { 22 createMaxdHeap(data, data.length - 1 - i); 23 swap(data, 0, data.length - 1 - i); 24 print(data); 25 } 26 } 27 28 public static void createMaxdHeap(int[] data, int lastIndex) { 29 for (int i = (lastIndex - 1) / 2; i >= 0; i--) { 30 // 保存当前正在判断的节点 31 int k = i; 32 // 若当前节点的子节点存在 33 while (2 * k + 1 <= lastIndex) { 34 // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点 35 int biggerIndex = 2 * k + 1; 36 if (biggerIndex < lastIndex) { 37 // 若右子节点存在,否则此时biggerIndex应该等于 lastIndex 38 if (data[biggerIndex] < data[biggerIndex + 1]) { 39 // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值 40 biggerIndex++; 41 } 42 } 43 if (data[k] < data[biggerIndex]) { 44 // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k 45 swap(data, k, biggerIndex); 46 k = biggerIndex; 47 } else { 48 break; 49 } 50 } 51 } 52 } 53 54 public static void print(int[] data) { 55 for (int i = 0; i < data.length; i++) { 56 System.out.print(data[i] + "\t"); 57 } 58 System.out.println(); 59 } 60 61 }
——使记录序列按关键字非递减有序排列,则在堆排序的算法中先建立一个“大顶堆”,即先选得一个关键字为最大的记录,并与序列中最后一个记录交换,然后对序列中前n-1记录进行筛选,重新将它调整为一个“大顶堆”,如此反复直至排序结束。
1 import java.util.*; 2 3 public class HeapSort { 4 public int[] heapSort(int[] A, int n) { 5 // write code here 6 for(int i=n/2; i>=0; i--){ 7 heapAdjust(A,i,n); 8 } 9 10 for(int i=n-1;i>0;i--){ 11 swap(A,0,i); 12 heapAdjust(A,0,i); 13 } 14 return A; 15 } 16 17 void heapAdjust(int[] A,int index,int length){ 18 int childLeft; 19 int temp = A[index]; 20 for( ;index*2+1 < length;index = childLeft){ 21 childLeft = index*2+1; 22 if(childLeft !=length-1 && A[childLeft] < A[childLeft+1]){ 23 childLeft++; 24 } 25 if(temp > A[childLeft]){ 26 break; 27 28 } 29 else { 30 A[index] = A[childLeft]; 31 index = childLeft; 32 } 33 } 34 A[index] = temp; 35 36 } 37 38 static void swap(int[] A,int m,int n){ 39 int temp = A[m]; 40 A[m] = A[n]; 41 A[n] = temp; 42 } 43 }

浙公网安备 33010602011771号