堆排序算法 總結

最近面試,老是被問到堆排序算法。
回答時老是感覺思路不清楚,現在總結一下,把思路弄清楚的。

1.堆排序是利用堆的特性對記錄序列進行排序的一種排序方法。
好的那麼堆得特性是什麼呢?
堆得定義:
堆是滿足下列性質的數列{r1, r2, …,rn}:

 
如下圖最開始是一個小頂堆。當把97和13 交換後不是堆了,所以我們要調整根節點使之成爲堆即篩選。(注意:是自堆頂到葉子的篩選過程,應該剛開始是堆由於把堆頂給換了,罪魁禍首是堆頂,其它小範圍還是堆,所以是從堆頂開始)。

這其中還要注意一點。97 與13 交換後應該跟27 比較爲什麼呢?
1.因爲是小頂堆,所以在97 的子節點裏選擇小者。如果把38放上去。38成了27的父節點比27大就不是小頂堆了。如果換成大頂堆就要比較把大的數據放上去。
所以程序裏交換時要先要比較一下。
程序如下:
  1. //堆調整算法  
  2. void HeapAdjust (HeapType &H, int s, int m)  
  3. {   // 已知 H.r[s..m]中記錄的關鍵字除 H.r[s] 之外  
  4.     //均滿足堆的特徵,本函數自上而下調整 H.r[s]  
  5.     //的關鍵字,使 H.r[s..m] 也成爲一個大頂堆  
  6.      rc = H.r[s];    // 暫存 H.r[s]   
  7.      for ( j=2*s; j<=m; j*=2 ) { // j 初值指向左孩子  
  8.     自上而下的篩選過程;  
  9.      }  
  10.      // 自上而下的篩選過程  
  11.       if ( j<m && H.r[j].key>H.r[j+1].key )  ++j;       
  12.              // 左/右“子樹根”之間先進行相互比較  
  13.              // 令 j 指示關鍵字較小記錄的位置  
  14.       if ( rc.key <= H.r[j].key )  break;   
  15.            // 再作“根”和“子樹根”之間的比較,  
  16.            // 若“>=”成立,則說明已找到 rc 的插  
  17.            // 入位置 s ,不需要繼續往下調整  
  18.   
  19.       H.r[s] = H.r[j];   s = j;      
  20.         // 否則記錄上移,尚需繼續往下調整  
  21.   
  22.     H.r[s] = rc;  // 將調整前的堆頂記錄插入到 s  (注意插入的位置爲s j=2*s)  
  23. // HeapAdjust  

2)建堆是一個從下往上進行“篩選”的過程 (首先要把底部的建成小堆,前面調整是因爲只有堆頂,其它都已經是堆了。當我建堆到堆頂是也是從堆頂往下篩選)(所以說建堆大範圍是從下往上篩選,在添加該結點時,還得從該節點往下篩選確保添加該節點後還是堆)。
如下圖建堆過程:  從97 開始->65->38 ->49這是從下往上(大範圍從下往上)。第二個圖到65時又 65與13 調整了(從上往下調整)。當到49時也是49<-> 13  <-> 27所以也是從上之下調整(爲了確保加入該結點後還是堆)。



程序如下:
堆排序算法如下:
  1. void HeapSort ( HeapType &H ) {  
  2.   // 對順序表 H 進行堆排序  
  3. for ( i=H.length/2;   i>0;   --i )  
  4.      HeapAdjust ( H.r, i, H.length );    // 建小頂堆  
  5.   
  6. for ( i=H.length; i>1; --i ) {  
  7.      H.r[1]←→H.r[i];             
  8.           // 將堆頂記錄和當前未經排序子序列  
  9.           //  H.r[1..i]中最後一個記錄相互交換  
  10.      HeapAdjust(H.r, 1, i-1);  // 對 H.r[1] 進行篩選  
  11. }  
  12. // HeapSort  

note: 堆排序算法以前看過幾遍老是忘,問得時候思路不太清晰。只要把關鍵幾個點弄清楚,把思路搞清楚了以後就不怕了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章