排序演算法 堆排序

2022-07-03 15:12:13 字數 2542 閱讀 5212

【原文: 

,分為大頂堆(大堆)和小頂堆(小堆),是順序儲存的完全二叉樹,並且滿足以下特性之一:

(1)    任意非終端結點關鍵字不小於左右子結點(大堆)

ki >= k2i+1並且ki>=k2i+2 其中,0 <= i <= (n-1)/2,n是陣列元素個數

(2)    任意非終端結點關鍵字不大於左右子結點(小堆)

ki <= k2i+1並且ki<=k2i+2 其中,0 <= i <= (n-1)/2,n是陣列元素個數

調整(也有叫篩選):

從當前結點(要求是非終端結點)開始,

對於大堆,要求當前結點關鍵字不小於子結點,如不符合,則將最大的子結點與當前結點交換。迴圈迭代交換後的子樹,確保所有子樹都符合大堆特性。

小堆調整過程類似。

堆排序就是利用構建堆和輸出堆頂元素的過程,不斷對堆進行調整以保證當前結點及其孩子結點滿足堆特性,從而達到對初始陣列元素進行排序的目的。

大堆通常對應公升序序列,小堆通常對應降序排列。

核心步驟:

1)構建堆(大堆/小堆)

從最後乙個非終端結點開始,向前進行調整,保證當前結點及其子樹符合堆特性;

2) 輸出有序序列

交換堆頂與末尾葉子結點,堆頂輸出到陣列的有序序列末尾,而不參與堆的調整。從交換後的堆頂開始調整,以確保當前結點及其子樹符合堆特性。

下面舉個例子,利用小堆進行降序排列。

初始序列

49『位置

1)      初始序列對應初始堆

從最後乙個非葉子結點開始,向前進行調整,確保符合特性

最後乙個非葉子結點位置:(n-1) / 2 = 3, n=8

總共調整次數:(n-1)/2 +1 = 4

第1次調整:選擇最後乙個非葉子結點元素為97(位置3)為當前父結點,與其子結點進行比較,選擇最小的結點作為當前父結點。

第1次調整後序列

49』位置

第2次調整後序列

49』位置

第3次調整後序列

49』位置

第4次調整後序列

49』位置

將已經構建好的小堆,輸出堆頂元素,和末尾元素交換,相當於堆頂移動到陣列末尾形成有序序列,未排序元素移動到堆頂。從新的堆頂開始進行調整,直到堆重新符合小堆特性。

交換堆頂和末尾(堆的末尾,不包括已經排好序的部分),並將交換後的堆末尾作為有序序列的一部分,而不再屬於堆。 

一次交換後,發現97新的位置比子結點大,需要繼續調整。

這樣,不斷輸出所有堆頂到陣列末尾,最終可以得到

有序序列

49』位置

1

//堆排序(小根堆)23

//i為調整的位置

4void heapadjust(int a, int i, int

len)510

11//

檢查結點i是否符合最大堆特性, 如果不符合, 需要與最大子結點交換

12for (int k = 2 * i + 1; k < len; k = 2 * k + 1)13

1920

if (a[i]

2127

else

//符合大堆特性

2831}32

}3334void heapsort(int arr, int

len)

3542

43//

再輸出並調整

44for (int j = len - 1; j > 0; j--) //

判斷條件不用加"=", 因為j=0時等價於陣列只有乙個元素, 即只有乙個根節點, 而無子樹

4551 }

排序演算法 堆排序

1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...

排序演算法 堆排序

花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...

排序演算法 堆排序

由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...