堆排序是怎么排的?


我們先看看究竟什么是堆?以大頂堆為例:

對於一棵完全二叉樹而言,當每個結點不小於其子結點時,便可稱之為堆(大頂堆),比如:

 

 

原始的待排序的數組為:30, 20, 40, 10, 0, 60, 80, 70其對應的完全二叉樹為:

 

 

接下來,我們來圖解堆排序,並用程序來實現堆排序。在這個過程中,希望大家感受到堆之美。

 

圖解堆排序

一. 構建堆

第1步:

如上圖,最后一個非葉子結點是10,發現10比70小,所以70必須上浮,得到的結果為:

 

 

 

第2步:

如上圖,倒數第二個非葉子結點為40,在40,60,80這三個數中,80最大,所以80必須上浮,得到的結果如下:

 

 

 

第3步:

如上圖,倒數第三個非葉子結點為20,而20比70小,所以70必須上浮,20下沉后,發現比下面的10還大,所以沒有必要沉底,得到的結果為:

 

 

 

第4步:

如上圖,倒數第四個非葉子結點為30,在30,70,80中,80最大,所以80要上浮,30下沉。然而,30比60和40都小,所以要繼續下沉,得到的結果是:

 

 

到此為止,可以看到,一個大頂堆已經形成,可以看到,最大的80已經被選擇出來了。

 

二. 調整堆

我們把堆頂的最大值80調整到最后,保存下來,得到的結果是:

 

 

接下來的工作就是對上面紅框中的的7個結點進行調整,使之形成新的堆。

很顯然,根據之前調整的過程可知,兩個藍色框中的結點,已經分別成堆了,所以這次的調整就簡單多了,直接瞄准待調整的10即可。

之前已經把8個結點調整成堆,那么調整上面紅色框中的7個結點成堆便不在話下。於是,這7個結點中最大的70被調到了堆頂,如下:

 

 

80是最大的值,放在最后。堆頂的70是第二大的值,放在倒數第二的位置,所以跟40進行交換,得到的結果為:

 

 

可見,通過2次從堆頂摘下最大元素,分別把80和70選出來了。接下來,用相同的方法,把60選出來,依此循環,最后得到的二叉樹為:

 

 

終於,實現了排序,這就是所謂的堆排序,其平均時間復雜度為O(N*logN), 比冒泡排序好多啦。

 

堆排序實現

接下來,我們用代碼來實現堆排序,如下:

#include<iostream>
using namespace std;

void print(int a[], int n)
{
  int i;
  for(i = 0; i < n; i++)
  {
    cout << a[i] << " ";
  }

  cout << endl;
}
 
void heapAdjust(int a[], int low, int high)
{
  int pivotKey = a[low - 1];
  int i;
  for(i = 2 * low; i <= high; i *= 2) 
  {
    if(i < high && a[i - 1] < a[i])
    {
      i++; //i指向較大值
    }

    if(pivotKey >= a[i - 1])
    {
      break;
    }
  
    a[low - 1] = a[i - 1];
    low = i; 
  }
  a[low - 1] = pivotKey; 
}
 
void heapSort(int a[], int n)
{
  int i, tmp;
  for(i = n/2; i > 0; i--) 
  {
    heapAdjust(a, i, n);
    print(a, n);
  }

  for(i = n; i > 1; i--)
  {
    tmp = a[i -1];
    a[i - 1] = a[0];
    a[0] = tmp;
    heapAdjust(a, 1, i - 1); 
    print(a, n);
  }
}

int main()
{
  int a[] = {30, 20, 40, 10, 0, 60, 80, 70};
  int n = sizeof(a) / sizeof(a[0]);
  heapSort(a, n);
  print(a, n);
  return 0;
}

 

最終的排序結果如下:

0 10 20 30 40 60 70 80 

 

堆是一種重要的數據結構,堆排序也是非常重要的算法。在筆試面試中,經常考到堆的相關應用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM