1. 程式人生 > >排序演算法七--堆排序

排序演算法七--堆排序

什麼是堆?  堆是一棵順序儲存的完全二叉樹。  小根堆:每個結點的關鍵字都不大於其孩子結點的關鍵字。  大根堆:每個結點的關鍵字都不小於其孩子結點的關鍵字。  對於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