堆排序(英語:Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
根據根結點是否是最大值還是最小值和子結點的鍵值是否小於還是大於它的父結點可分為兩種堆,如下:
1.大頂堆:每個結點的鍵值都小於它的父結點;
2.小頂堆:每個結點的鍵值都大於它的父節點;
堆排序基本思想:
1.將數組排列成大頂堆(或小頂堆);
2.把根結點和尾結點交換,然后把n-1個元素重新構成一個大頂堆(或小頂堆);
3.重復第2步,直到最后一個元素。
流程圖(為了不太麻煩,所以就減少些數據):
一,先將數組排序成大頂堆
二,把根結點和末尾結點交換
代碼:
1 /** 2 * 堆排序 3 */ 4 public class TestHeap { 5 //創建大頂堆 6 public static void maximumHeap(int k, int[] arr,int m) { 7 int i, j, temp; 8 boolean finished; 9 i = k; 10 j = 2*i+1; 11 temp = arr[k]; 12 finished = false; 13 while((j <= m) && !finished){ 14 //孩子結點位置小於數組長度 且 右孩子大於左孩子 15 if ((j < m) && (arr[j+1] > arr[j])){ 16 j++; //把右孩子結點當作最大孩子結點 17 } 18 //如果最大的孩子結點小於其根節點 19 if (temp >= arr[j]){ 20 finished = true; //結束循環 21 }else{ 22 //把最大子節點賦給根結點 23 arr[i] = arr[j]; 24 i = j; 25 //循環下一個根結點 26 j = 2*j+1; 27 } 28 } 29 arr[i] = temp; 30 } 31 32 //交換 33 public static void heapsort(int[] arrays) { 34 int i; 35 //從最后一個非葉節點開始構建大頂堆 36 for (i = arrays.length / 2 - 1; i >= 0; i--) { 37 maximumHeap(i, arrays, arrays.length); 38 } 39 System.out.println("建堆后:" + Arrays.toString(arrays)); 40 //從最小的葉子節點開始與根節點進行交換並重新構建大頂堆 41 for (i = arrays.length - 1; i >= 1; i--) { 42 int temp = arrays[i]; 43 arrays[i] = arrays[0]; 44 arrays[0] = temp; 45 maximumHeap(0, arrays,i-1); 46 } 47 System.out.println(Arrays.toString(arrays)); 48 } 49 50 public static void main(String[] args) { 51 int[] arrays = {49, 38, 65, 97, 176, 213, 227, 49, 78, 34, 12, 164, 11, 18, 1}; 52 heapsort(arrays); 53 } 54 }
測試結果:
建堆后:[227, 176, 213, 97, 38, 164, 65, 49, 78, 34, 12, 49, 11, 18, 1] [1, 11, 12, 18, 34, 38, 49, 49, 65, 78, 97, 164, 176, 213, 227]
時間復雜度:堆排序方法對記錄數n較大的文件排序是很好的,但當n較小時,不提倡使用,因為初始建堆和調整建新堆時要進行反復的篩選。堆排序時間復雜度為O(nlog2n)。
堆排序只需存放一個記錄的附加空間。
堆排序是一種不穩定的排序算法。
結語:堆排序是為了即要保存中間比較結果,減少后面的比較次數,又不占用大量的附加存儲空間,使排序算法具有較好的性能才被Willioms和Floyd在1964年提出的。