前言:今天我來介紹下堆排序,在寫堆排序**之前,我們要知道堆的概念!
堆的定義:n個關鍵字序列kl,k2,…,kn稱為(heap),當且僅當該序列滿足如下性質(簡稱為堆性質):
(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),當然,這是小根堆,大根堆則換成》=號。//k(i)相當於二叉樹的非葉子結點,k(2i)則是左子節點,k(2i+1)是右子節點
若將此序列所儲存的向量r[1..n]看做是一棵完全二叉樹的儲存結構,則堆實質上是滿足如下性質的完全二叉樹:
樹中任一非葉子結點的關鍵字
均不大於(或不小於)其左右孩子(若存在)結點的關鍵字。
堆的分類:
1).大根堆和小根堆:根結點(亦稱為堆頂)的
關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。
2).根結點(亦稱為堆頂)的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。
注意:①堆中任一子樹亦是堆。②以上討論的堆實際上是二叉堆(binary heap),類似地可定義k
堆排序的思想:
1).先將初始檔案r[1..n]建成乙個大根堆,此堆為初始的無序區
2).再將關鍵字最大的記錄r[1](即堆頂)和無序區的最後乙個記錄r[n]交換,由此得到新的無序區r[1..n-1]和有序區r[n],且滿足r[1..n-1].keys≤r[n].key
3).由於交換後新的根r[1]可能違反堆性質,故應將當前無序區r[1..n-1]調整為堆。然後再次將r[1..n-1]中關鍵字最大的記錄r[1]和該區間的最後乙個記錄r[n-1]交換,由此得到新的無序區r[1..n-2]和有序區r[n-1..n],且仍滿足關係r[1..n-2].keys≤r[n-1..n].keys,同樣要將r[1..n-2]調整為堆。
1//堆排序,偽**2//
heapsort(a)3//
build-max-heap(a)4//
for i=a.length downto 25//
exchange a[1] with a[i]
//將第乙個元素和第i個元素交換6//
a.heap-size = a.heap-size - 1;7//
max-hep-apify(a,1);89
void heapadjust(int iarr,int start,int
len)
1019
if(iarr[i] 2025}26
}27void heapsort(int iarr,int
len)
2835
for(i = 0;i < len; ++i)
3639 cout <40for(i = len - 1; i > 0; --i)
4148}49
intmain()50;
52 heapsort(a,10
);53
for(int i=0;i < 10; ++i)
54 cout << a[i] << "";
55return0;
56 }
演算法分析:
堆排序的時間,主要由建立初始堆和反覆重建堆這兩部分的時間開銷構成,它們均是通過呼叫heapadjust實現的。
平均效能:o(n*logn) = o(n)(heapsort中的兩個for迴圈的時間複雜度)*o(lonn)(heapadjust中的for迴圈的時間複雜度)。
由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的檔案。
堆排序是就地排序,輔助空間為o(1).
它是不穩定的排序方法。
排序演算法之堆排序
堆排序演算法是選擇排序的一種,該演算法只是通過堆,最大堆 或者最小堆選擇出乙個待排序序列中的最大值,或者最小值。要想實現堆排序演算法,就需要構建什麼堆,這裡也最小堆為例。說明什麼是堆,怎麼構建乙個堆。假設待排序序列為a n 為乙個陣列。陣列的長度為n 陣列下標為 0,1,2,i,2i,2i 1 n ...
排序演算法之堆排序
宣告 本博文 為樓主親自編寫並測試,其它內容引用至我一直很崇拜的牛人morewindows。他對排序演算法的講解通俗易懂,給人一種耳目一新的感覺。堆排序與快速排序 歸併排序 一樣都是時間複雜度為o n logn 的幾種常見排序方法。最小堆的講解以及最小堆元素的插入和刪除參見最小堆操作。以下繼續引用以...
排序演算法之堆排序
堆排序是一種樹形選擇排序,是對直接選擇排序的有效改進。堆是一種資料結構,其定義 任何乙個非葉結點的值,都不大於 或不小於 其左右孩子結點的值。若父親大孩子小,則這樣的堆叫做大頂堆 若父親小孩子大,則這樣的堆叫做小頂堆。顧名思義,大頂堆的根結點的值是最大的,小頂堆的根結點的值是最小的。首先,將乙個無序...