排序演算法總結之堆排序

飛翔的黃瓜發表於2017-08-03

堆排序算是選擇排序,即按照最小堆的方式,一個一個彈出來,不過這樣子需要額外的陣列來存放彈出來的資料。浙江大學陳越老師的方法,不需要額外的陣列,如下


利用陣列的方式建立一個最大堆

它的工作方式是:每次把最大堆的根節點和下標最大的結點(不一定是數值最小)交換,這樣下標最大的結點即為最大值,如圖所示,a和b交換,a在根節點而b交換到了堆偉。然後把堆的規模減1,如圖即把下邊為3的結點斷了與這個堆的聯絡。這樣最大值就已經放在了排序陣列中它應該在的位置。下一次交換之前先進行下濾,即讓堆重新變為最大堆再次進行交換,一次類推。具體實現程式碼如下

void Swap( ElementType *a, ElementType *b )
{
     ElementType t = *a; *a = *b; *b = t;
}
  
void PercDown( ElementType A[], int p, int N )
{ /* 改編程式碼4.24的PercDown( MaxHeap H, int p )    */
  /* 將N個元素的陣列中以A[p]為根的子堆調整為最大堆 */
    int Parent, Child;
    ElementType X;
 
    X = A[p]; /* 取出根結點存放的值 */
    for( Parent=p; (Parent*2+1)<N; Parent=Child ) {
        Child = Parent * 2 + 1;
        if( (Child!=N-1) && (A[Child]<A[Child+1]) )
            Child++;  /* Child指向左右子結點的較大者 */
        if( X >= A[Child] ) break; /* 找到了合適位置也可能一次也不需要交換 */
        else  /* 下濾X */
            A[Parent] = A[Child];
    }
    A[Parent] = X;
}
 
void HeapSort( ElementType A[], int N ) 
{ /* 堆排序 */
     int i;
       
     for ( i=N/2-1; i>=0; i-- )/* 建立最大堆 */
         PercDown( A, i, N );
      
     for ( i=N-1; i>0; i-- ) {//i=N-1因為是從小標0開始的
         /* 刪除最大堆頂 */
         Swap( &A[0], &A[i] ); /* 見程式碼7.1 */
         PercDown( A, 0, i );//這裡知道0結點不是最大值即對0結點下濾
     }
}


相關文章