排序演算法七--堆排序
阿新 • • 發佈:2018-12-16
什麼是堆? 堆是一棵順序儲存的完全二叉樹。 小根堆:每個結點的關鍵字都不大於其孩子結點的關鍵字。 大根堆:每個結點的關鍵字都不小於其孩子結點的關鍵字。 對於n個元素的序列{R0, R1, … , Rn}當且僅當滿足下列關係之一時,稱之為堆: (1) Ri <= R2i+1 且 Ri <= R2i+2 (小根堆) (2) Ri >= R2i+1 且 Ri >= R2i+2 (大根堆) 利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。 其基本思想為(大頂堆): 1)將初始待排序關鍵字序列(R1,R2….Rn)構建成大頂堆,此堆為初始的無序區; 2)將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,……Rn-1)和新的有序區(Rn),且滿足R[1,2…n-1]<=R[n]; 3)由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,……Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2….Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。
平均時間複雜度:O(NlogN) 由於每次重新恢復堆的時間複雜度為O(logN),共N - 1次重新恢復堆操作,再加上前面建立堆時N / 2次向下調整,每次調整時間複雜度也為O(logN)。二次操作時間相加還是O(N * logN)。
程式碼實現:
//構建最小堆 public static void MakeMinHeap(int a[], int n){ for(int i=(n-1)/2 ; i>=0 ; i--){ MinHeapFixdown(a,i,n); } } //從i節點開始調整,n為節點總數 從0開始計算 i節點的子節點為 2*i+1, 2*i+2 public static void MinHeapFixdown(int a[],int i,int n){ int j = 2*i+1; //子節點 int temp = 0; while(j<n){ //在左右子節點中尋找最小的 if(j+1<n && a[j+1]<a[j]){ j++; } if(a[i] <= a[j]) break; //較大節點下移 temp = a[i]; a[i] = a[j]; a[j] = temp; i = j; j = 2*i+1; } } public static void MinHeap_Sort(int a[],int n){ int temp = 0; MakeMinHeap(a,n); for(int i=n-1;i>0;i--){ temp = a[0]; a[0] = a[i]; a[i] = temp; MinHeapFixdown(a,0,i); } }
部分參考:https://blog.csdn.net/lyhkmm/article/details/78920769