(6)排序之堆排序

2022-08-23 14:45:10 字數 2852 閱讀 1281

文章** --靜默空間

堆的概念

在介紹堆排序之前,首先需要說明一下,堆是個什麼玩意兒。

是一棵順序儲存完全二叉樹

其中每個結點的關鍵字都不大於其孩子結點的關鍵字,這樣的堆稱為小根堆

其中每個結點的關鍵字都不小於其孩子結點的關鍵字,這樣的堆稱為大根堆

舉例來說,對於n個元素的序列當且僅當滿足下列關係之一時,稱之為堆:

(1) ri <= r2i+1且 ri <= r2i+2 (小根堆)

(2) ri >= r2i+1且 ri >= r2i+2 (大根堆)

其中i=1,2,…,n/2向下取整; 

如上圖所示,序列r是乙個典型的小根堆。

堆中有兩個父結點,元素3和元素8。

元素3在陣列中以r[0]表示,它的左孩子結點是r[1],右孩子結點是r[2]。

元素8在陣列中以r[1]表示,它的左孩子結點是r[3],右孩子結點是r[4],它的父結點是r[0]。可以看出,它們滿足以下規律

設當前元素在陣列中以r[i]表示,那麼,

(1) 它的左孩子結點是:r[2*i+1];

(2) 它的右孩子結點是:r[2*i+2];

(3) 它的父結點是:r[(i-1)/2];

(4) r[i] <= r[2*i+1] 且 r[i] <= r[2i+2]。

要點

首先,按堆的定義將陣列r[0..n]調整為堆(這個過程稱為建立初始堆),交換r[0]和r[n];

然後,將r[0..n-1]調整為堆,交換r[0]和r[n-1];

如此反覆,直到交換了r[0]和r[1]為止。

以上思想可歸納為兩個操作:

(1)根據初始陣列去構造初始堆(構建乙個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。

(2)每次交換第乙個和最後乙個元素,輸出最後乙個元素(最大值),然後把剩下元素重新調整為大根堆。 

當輸出完最後乙個元素後,這個陣列已經是按照從小到大的順序排列了。

先通過詳細的例項圖來看一下,如何構建初始堆。

設有乙個無序序列 。

構造了初始堆後,我們來看一下完整的堆排序處理:

還是針對前面提到的無序序列 來加以說明。

核心**

#include#include

#include

#include

using

namespace

std;

void adjust(int arr, int len, int

index)

}void heapsort(int arr, int

size)

for(int i = size - 1; i >= 1; i--)

}int

main()

; heapsort(array, 8);

for(auto it: array)

return0;

}

排序類別排序方法時間複雜度

空間複雜度

穩定性

複雜性

平均情況

最壞情況

最好情況

選擇排序

堆排序o(nlog2n)

o(nlog2n)

o(nlog2n)

o(1)

不穩定較複雜

堆的儲存表示是順序的。因為堆所對應的二叉樹為完全二叉樹,而完全二叉樹通常採用順序儲存方式。

當想得到乙個序列中第k個最小的元素之前的部分排序序列,最好採用堆排序。

因為堆排序的時間複雜度是o(n+klog2n),若k≤n/log2n,則可得到的時間複雜度為o(n)

堆排序是一種不穩定的排序方法。

因為在堆的調整過程中,關鍵字進行比較和交換所走的是該結點到葉子結點的一條路徑,

因此對於相同的關鍵字就可能出現排在後面的關鍵字被交換到前面來的情況。 

33 排序演算法(6) 堆排序

之前所講的演算法,很多都是 o n2 的,造成這些演算法複雜度較高的主要原因是它們一次又一次地重複地進行這比較操作,並沒有利用之前的比較得到的結果。希爾排序對直接插入排序進行改進,使得這種方法的複雜度從 o n2 下降到 o nlog n 在這裡我們將接著介紹一種利用之前排序結果的方法,堆排序。若設...

18 排序 堆排序

void selection sort elementtype a,int n 中找到最小元,並將其位置賦給minposition minposition scanformin a,i,n 1 將未排序部分的最小元換到有序部分的最後位置 swap a i a minposition 時間複雜度 t ...

8 排序演算法 堆排序

堆排序 heapsort 是指利用堆這種資料結構所設計的一種排序演算法。堆積是乙個近似完全二叉樹的結構,並同時滿足堆積的性質 即子結點的鍵值或索引總是小於 或者大於 它的父節點。堆排序可以說是一種利用堆的概念來排序的選擇排序。分為兩種方法 堆排序的平均時間複雜度為 nlogn 1.演算法步驟 建立乙...