堆排序在我看來是乙個比較難的排序演算法,專門記錄一下吧。
首先,先簡單介紹一下堆這種結構。
堆排序,顧名思義,是利用堆這一資料結構進行的。堆是一種特殊的二叉樹,其中每個元素都符合一定的規則。
最大堆:每乙個父節點,都比兩個子節點大。最小堆就是父節點比子節點小。
當然陣列是是一段順序表,並不是這樣的結構,現在以最大堆為例,將圖上每乙個點編上號。序號為從上到下,從左到右。
不難看出最大堆的一種性質:每個節點的下標乘2,乘2+1所獲得的下標就是該節點的兩個子節點的下標
這時就可以把最大堆的性質用數學形式表現出來了。對於最大堆的每乙個節點,都有\(arr[i]>=arr[i*2]\&\&arr[i]>=arr[i*2+1]\)
從現在開始模擬一下堆排序的執行原理,其中還需要一些其他的函式,下面再說。
現在有一組元素已經按最大堆的方式排列就緒,從最後乙個節點進行迴圈,直到只剩乙個未經排序的節點為止。
對於每乙個節點,將在堆頂的元素與當前節點交換。因為堆頂的元素是這個堆最大的元素,所以我們就找到了最大值的位置,並將它的值排在未經排序的序列的最後乙個位置,也就是說排好了乙個資料。
但是,經過交換後的堆,已經不滿足最大堆的條件了,我們再用乙個函式adjust_heap來將其重新恢復到最大堆的狀態。接下來一直執行到迴圈結束為止。其實堆排序的主函式還是挺好寫的。
void heapsort(int *arr,int length)
/*for (int i=0;i不過有兩個問題。
怎麼實現adjust_heap?
怎麼把乙個不滿足最大堆的陣列轉換為最大堆?
第二個問題是依靠第乙個問題的adjust_heap函式來實現的,先來看adjust_heap的工作原理。
adjust_heap如上文所述,是用來恢復最大堆的。再具體一點,這個函式需要知道當前不符合最大堆元素的位置,進行恢復的資料的範圍。(後者很顯而易見,不能把已經排好序的數字當作未排序的又放回原來位置吧)
這個函式的執行機制就是從給定的父節點開始,從兩個子節點中選取最大的乙個,並比較父節點與較大的子節點,如果父節點是最大的,說明已經處理完畢;否則交換這兩個節點,繼續向下比較。
void heapadjust(int *arr,int top,int range)//arr為陣列首位址,top為需要進行恢復的元素下標,range就是範圍啦
}
剩下的問題就只有乙個了,如何將乙個一般陣列變換為最大堆的結構?這裡我們用initialize_heap函式來實現。實現方式也很簡單粗暴,對一半的資料都adjust一遍就行了。
當然還是要解釋一遍要對一半的資料進行調整。上面說過乙個資料的下標*2就可以得到其子節點的下標,反過來說,只有這個資料的下標*2小於等於總資料個數的時候才會有子節點因此從有子節點的遍歷處理一遍就好了當然全部過一遍也沒什麼問題。
void initheap (int *arr,int length)
堆排序就寫完啦~ 堆的簡介以及堆排序
什麼是堆?堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質 key i key 2i 1 key i key 2i 2 或者 key i key 2i 1 key key 2i 2 即任何一非葉節點的關鍵字不大於或者不小於其左右孩子節點的關鍵字。堆分為大頂堆和小頂堆,滿足 key i key 2i...
堆排序 堆排序優化 索引堆排序
堆排序 堆排序優化 索引堆排序 注 堆排序 索引堆排序 都是不穩定的排序。注 索引最大堆排序有誤!有沒有大神可以指點一二?1 堆 所有元素 都從索引0開始 父親結點索引 i 左孩子結點索引 2i 1 右孩子結點索引 2i 2 左後乙個非葉子結點索引 n 1 2 用於構建堆,從最後乙個非葉子結點索引開...
堆排序 堆排序優化 索引堆排序
堆排序 堆排序優化 索引堆排序 注 堆排序 索引堆排序 都是不穩定的排序。注 索引最大堆排序有誤!有沒有大神可以指點一二?1 堆 所有元素 都從索引0開始 父親結點索引 i 左孩子結點索引 2i 1 右孩子結點索引 2i 2 左後乙個非葉子結點索引 n 1 2 用於構建堆,從最後乙個非葉子結點索引開...