堆排序 heap sort 演算法講解與實現

2021-08-31 18:37:01 字數 3058 閱讀 8616

開始時,堆不可能是這個樣子,因為,將陣列轉化為樹,是有規則的,必須把左邊填滿才能再填右邊。

待排序陣列:a = [46,30,82,90,56,17,95],組成乙個二叉樹,將46,30,82,90,56,17,95這幾個數字從儲存在陣列結構,轉變到二叉樹及結構,是通過為一些陣列下標賦予一些新的關係。比如,在陣列中索引0和2的關係是,2是0的後兩個元素,而在二叉樹中,2是0的右子樹。

第一步,將這樣乙個二叉樹轉化為堆。堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。

從二叉樹的倒數第二層的最右邊開始,之所以從最右邊,是因為我們在程式實現的時候,都是左節點和節點比較,如果節點比左節點大且比雙親節點大,則將節點與雙親節點交換。

如果不用程式,我們自己按照堆排序演算法思想排序,那那從左邊開始,或者從右邊開始都可以,但是,如果是用程式實現,我們的程式最好按照統一的規則,這樣有利於我們實現演算法。而不是一會從最右邊開始,一會從最左邊開始,不是不能實現,而是不方便實現。

初始化i=n/2-1,注意:n是陣列長度。

比較2i+1和2i+2,將其中比較大的乙個與a[i]交換,也就是與父節點交換。由於95>17,95>82,所以,95和82互換。

移動以後的結果如上圖所示。

然後i-1,比較2i+1和2i+2,將較大的元素的索引值賦值給l,如果a[l] > a[i],則將a[l]與a[i]交換。

交換以後的結果如上圖所示。

然後i-1,比較a[2i+1]和a[2i+2],將較大的數的索引下標賦值給l,記錄下來,然後a[l],也就是如果子節點中較大的乙個大於父節點,則將其與父節點交換。

此時,95的右邊子樹又被打亂了。

繼續移動i,讓i指向46這棵子樹,然後調整這棵樹。

交換後,結果如上圖所示。

然後i-1,指向95的左節點,調整該子樹。由於該子樹本來滿足堆的條件,所以不用調整。

然後繼續i-1,指向95,也不用調整。95大於兩個子節點90和46,所以也不用調整。

此時,你會發現,每乙個節點都大於等於其左右孩子的值,我們就完成了從乙個二叉樹到堆的轉變。

當然,這只是準備工作,我們的目標是排序,不是構造堆。

將最後乙個節點,也就是a[6],與a[0]做交換,然後,此時i指標只需要從上向下調整一遍即可。但是調整時不再考慮a[6],就當樹裡沒有a[6]。

注意:是從上到下,不是從下到上。

我們得到了上圖

我們對a[5],a[4],a[3],a[2],a[1]依次執行上述操作,也就是從前到後,每次跟變換以後新得到的a[0]交換。

最終我們得到了上圖結果,此時a[0]到a[6]為乙個依次遞增序列。

演算法在第二個階段的特點是:

子頂向下調整

第i次迴圈根結點與n-i結點交換位置(n為節點數),並且,在調整過程中,不考慮移動下來的根結點。

for (i = n / 2 - 1; i >= 0; i--)
這句話裡i = n/2-1表示從最後乙個非葉子節點開始調整。

如果你的樹是tree1這樣的,倒數第二層最後乙個節點沒孩子即a[2],那麼,n/2 - 1  = 1,也就是,當下標2沒有孩子,指標不會從下標2開始,因為它沒有孩子,不需要調整。

但如果a[2]只有乙個孩子,如tree2,n/2-1 = 2,指標都會從下標2開始,因為a[2]是有孩子,所以,我個人認為,這句話非常有意思

這個圖從a[3]開始調整,而不是a[2]

for (; l <= end; c = l, l = 2 * l + 1)//將c設定為其左孩子,l設定為右孩子
l是當前所在下標,end是最後乙個節點下標,l<=end,說明l還有孩子節點,則進入迴圈;如果l已經沒有孩子節點了,則不再進入迴圈。

if (l < end && a[l] < a[l + 1])//如果右孩子小於end,並且,右孩子小於左孩子
這裡lc++實現**

/*a為待排序陣列,start為0,end為length(a)-1,改函式用於執行構建堆*/

void maxheap_down(int a, int start, int end) }}

/*a為待排序陣列,n為length(a)*/

void heap_sort_asc(int a, int n)

}

演算法思想:

**實現:

堆排序 Heap Sort 演算法(C C)

堆排序演算法基於選擇排序的思想,利用堆結構和二叉樹的一些性質來完成資料的排序。對堆中的結點按層進行編號,將其對映到陣列中會有以下特點 小頂堆 每個結點的值都小於或等於其左右子結點的值。a i a 2 i 1 a i a 2 i 2 大頂堆 每個結點的值都大於或等於其左右子結點的值。a i a 2 i...

經典排序演算法 堆排序Heap sort

經典排序演算法 堆排序heap sort 堆排序有點小複雜,分成三塊 第一塊,什麼是堆,什麼是最大堆 第二塊,怎麼將堆調整為最大堆,這部分是重點 第三塊,堆排序介紹 第一塊,什麼是堆,什麼是最大堆 什麼是堆 這裡的堆 二叉堆 指得不是堆疊的那個堆,而是一種資料結構。堆可以視為一棵完全的二叉樹,完全二...

經典排序演算法 堆排序(Heap Sort)

首先堆是乙個完全二叉樹,但同時他具有這樣的要求 每乙個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆 每乙個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。如下圖是乙個大頂堆 在此要補充乙個二叉樹的性質 二叉樹的某個節點下標為i,則它的左孩子的下標一定為2i,右孩子下標一定為2i 1。假如現...