摘要:
作為選擇排序的改進版,堆排序可以把每一趟元素的比較結果儲存下來,以便我們在選擇最小/大元素時對已經比較過的元素做出相應的調整。
堆排序是一種樹形選擇排序,在排序過程中可以把元素看成是一顆完全二叉樹,每個節點都大(小)於它的兩個子節點,當每個節點都大於等於它的兩個子節點時,就稱為大頂堆,也叫堆有序; 當每個節點都小於等於它的兩個子節點時,就稱為小頂堆。
(大頂堆(有序堆))
(小頂堆)
演算法思想(以大頂堆為例):
1.將長度為n的待排序的陣列進行堆有序化構造成乙個大頂堆
2.將根節點與尾節點交換並輸出此時的尾節點
3.將剩餘的n -1個節點重新進行堆有序化
4.重複步驟2,步驟3直至構造成乙個有序序列
假設待排序陣列為[20,50,10,30,70,20,80]
構造堆
在構造有序堆時,我們開始只需要掃瞄一半的元素(n/2-1 ~ 0)即可,為什麼?
因為(n/2-1)~0的節點才有子節點,如圖1,n=8,(n/2-1) = 3 即3 2 1 0這個四個節點才有子節點
(圖1:初始狀態)
所以**4~6行for迴圈的作用就是將3 2 1 0這四個節點從下到上,從右到左的與它自己的子節點比較並調整最終形成大頂堆,過程如下:
第一次for迴圈將節點3和它的子節點7 8的元素進行比較,最大者作為父節點(即元素60作為父節點)
【紅色表示交換後的狀態】
第二次for迴圈將節點2和它的子節點5 6的元素進行比較,最大者為父節點(元素80作為父節點)
第三次for迴圈將節點1和它的子節點3 4的元素進行比較,最大者為父節點(元素70作為父節點)
第四次for迴圈將節點0和它的子節點1 2的元素進行比較,最大者為父節點(元素80作為父節點)
(注意這裡,元素20和元素80交換後,20所在的節點還有子節點,所以還要再和它的子節點5 6的元素進行比較,這就是28行** i = j 的原因)
至此有序堆已經構造好了!如下圖:
調整堆
下面進行while迴圈
(1)堆頂元素80和尾40交換後–>調整堆
(2)堆頂元素70和尾30交換後–>調整堆
(3)堆頂元素60尾元素20交換後–>調整堆
(4)其他依次類推,最終已排好序的元素如下:
**實現
public class heapsort
while (len >=0)
}public static void heapadjust(int arr,int i,int len)
} public static void swap(int arr,int i,int len)
public static void main(string args) ;
system.out.println(「排序之前:」);
for(int element : array)
heapsort(array);
system.out.println(「\n排序之後:」);
for(int element : array)
} }
輸出:
排序之前:
20 50 20 40 70 10 80 30 60
排序之後:
10 20 20 30 40 50 60 70 80
堆排序主要在於理解堆的構造過程和在輸出最大元素後如何對堆進行重新調整,借助ide工具的除錯功能可以很好的幫助理解整個排序過程。
排序演算法 堆排序
1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...
排序演算法 堆排序
花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...
排序演算法 堆排序
由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...