【排序算法】堆排序白話講解

  堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。

選擇排序每次掃描出一個最小元素,與指定位置的元素進行互換

  可以利用數組的特點快速定位指定索引的元素。

  堆排序就是把最大堆堆頂的最大數取出,將剩餘的堆繼續調整爲最大堆,再次將堆頂的最大數取出,這個過程持續到剩餘數只有一個時結束。

堆的概念

   堆是一種特殊的完全二叉樹(complete binary tree)。

  完全二叉樹的一個"優秀"的性質是,除了最底層之外,每一層都是滿的,這使得堆可以利用數組來表示(普通的一般的二叉樹通常用鏈表作爲基本容器表示),每一個結點對應數組中的一個元素。
在這裏插入圖片描述
  對於給定的某個結點的下標 i,可以很容易的計算出這個結點的父結點、孩子結點的下標:

  • Parent(i) = floor(i/2),i 的父節點下標

  • Left(i) = 2i,i 的左子節點下標

  • Right(i) = 2i + 1,i 的右子節點下標

最大堆:

在這裏插入圖片描述

最大堆中的最大元素值出現在根結點(堆頂)

堆中每個父節點的元素值都大於等於其孩子結點(如果存在)

最小堆:

在這裏插入圖片描述
  最小堆中的最小元素值出現在根結點(堆頂)

  堆中每個父節點的元素值都小於等於其孩子結點(如果存在)

堆排序原理

在這裏插入圖片描述
  堆排序就是把最大堆堆頂的最大數取出,將剩餘的堆繼續調整爲最大堆,再次將堆頂的最大數取出,這個過程持續到剩餘數只有一個時結束。

  在堆中定義以下幾種操作:

   最大堆調整(Max-Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點

   創建最大堆(Build-Max-Heap):將堆所有數據重新排序,使其成爲最大堆

   堆排序(Heap-Sort):移除位在第一個數據的根節點,並做最大堆調整的遞歸運算 繼續進行下面的討論前,需要注意的一個問題是:

數組都是 Zero-Based,這就意味着我們的堆數據結構模型要發生改變(堆中0位置存放哨兵元素)

在這裏插入圖片描述
相應的,幾個計算公式也要作出相應調整:

Parent(i) = floor((i-1)/2),i 的父節點下標

Left(i) = 2i + 1,i 的左子節點下標*Right(i) = 2(i + 1),i 的右子節點下標

堆的建立和維護

  (1)將N個元素按輸入順序存入,先滿足完全二義樹的結構特性

  (2)調整各結點位置,以滿足最大堆的有序特性

   選取第一個含有子節點的節點((N-1)/2)開始,將其與子元素比較調整位置,然後再選擇前一個結點重複操作,直到獲取到一個堆爲止

   需要兩個循環,第一個循環遍歷從尾結點的父節點到根節點,第二個循環調整第一個循環選中結點保證該節點下符合堆結構

算法描述

在這裏插入圖片描述

方法一

  我們需要一個升序的序列,可以建立一個最小堆,然後每次輸出根元素。

  但是,這個方法需要額外的空間(否則將造成大量的元素移動,其複雜度會飆升到O(n2) )。

方法二

  我們可以建立最大堆,然後我們倒着輸出,在最後一個位置輸出最大值,次末位置輸出次大值…

  由於每次輸出的最大元素會騰出第一個空間,因此,我們恰好可以放置這樣的元素而不需要額外空間。

每次將堆頂元素與堆尾元素互換,然後再次調整取出輸出元素的數組爲最大堆,重複操作

代碼

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-- ) {
         /* 刪除最大堆頂 */
         Swap( &A[0], &A[i] ); /* 見代碼7.1 */
         PercDown( A, 0, i );
     }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章