鏈式結構實現堆排序

2022-03-29 13:37:07 字數 2036 閱讀 1474

在很多資料結構和演算法的書上,「堆排序」的實現都是建立在陣列上,陣列能夠通過下標訪問其元素,其這一特性在堆排序的實現上,使得其編碼實現比鏈式結構簡單,下面我利用鍊錶實現堆排序。在「堆」這種資料結構中,分為「大根堆」和「小根堆」,「大根堆」中其每乙個雙親節點大於等於其子女節點,「小根堆」的定義與其相

反, 當然實現最大堆之前必須要建乙個堆,乙個高度為h的堆,它的前h-1層時滿的,如下圖所示:

通過對上圖的直觀的感受,其構成是一課完全二叉樹,在完全二叉樹中,每乙個節點時按照層數來放置的,只有每一層放滿了之後才會進入下一層,所以建完全二叉樹的時候就需要按層建節點,下圖為其建完全二叉樹的過程:

在建完全二叉樹時每掛乙個節點時,該節點就要入隊,但是什麼時候出隊時個關鍵的問題,觀察每次的掛節點會發現,當雙親節點把右節點掛完之後(即雙親節點的左右子女都不為空),雙親節點會改變,但也會出現最後乙個節點出現只有乙個左子女的情況,但是這種情況會隨著迴圈而結束,因為這個節點的位置就是掛的最後乙個節點。

下面是其**的具體實現過程:

node *buildcompletebtree(int *a, int heap_size, node **pqueue)  

else  

}  }  

return root;  

}  其中front 和 rear 為全域性變數,初始值為1。

完全二叉樹建完後只是完成了第一步工作,要使這棵完全二叉樹變為堆,還需要對這棵樹進行調整,使其保持每乙個雙親節點大於等於其子女節點的屬性,其中根節點為這個堆中的最大值。

在調整中會發現從根節點向下調整時無法一次將最大值調整到根節點上去,所以我們由下往上將最大值向上推,如圖是調整一次後的結果:

從上面的一次調整可以看出,由下向上調整時雖然可以將當前所有資料的最大值推到根上但是並不能完成建最大堆的工作,所以我們需要反覆調整才能達到目的,其**實現的過程如下:

void max_heapify(node **pqueue)  

--k;  

}  if(!flag) break;  

}  }  

其中值得注意的問題是,要從下往上調整,需要最後乙個雙親的位置,那麼如何確定位置了,答案就是front,陣列中front中的值就是當前的雙親,而front前面的值都是雙親,注意到這一點的話後面的問題就迎刃而解,注意在調整的過程中front的是不能改變的,我們可以設定另乙個值等於front,這裡我們用變數k,所以每次跑迴圈的時候是k在跑,而front一直標識著最後乙個雙親節點的位置;但是在一次調整後如何判斷本次調整是不是將堆調成了最大堆呢?這裡我們想想當當前的堆是最大堆時再進行調整時是不會出現交換過程的,所以當堆變為最大堆時,交換過程是不會不出現的,所以我設定了乙個標誌flag來標記是否進行了交換,若出現了交換flag = 1,若沒有交換flag =  0,最後通過判斷flag的值來判斷當前堆的狀態。

在建好最大堆後後面的工作就簡單了,首先將根節點的值和最後乙個節點交換,然後刪除最後乙個節點,然後再調整改變了大小的堆使其保持最大堆,然後迴圈這個過程,直至只剩下乙個節點,下圖為刪除乙個節點的過程:

然後輸出的時候只要遍歷佇列輸出就可以輸出有序的序列了!堆排序是一種穩定的排序演算法,其演算法的時間複雜度為o(nlgn)。

堆排序《一》 簡單結構堆排序

堆排序 利用最大堆 最小堆完成排序 用陣列儲存,但邏輯結構為 完全二叉樹 heapelem arr 物理結構 邏輯結構 i 3 要調整的結點 j i 2 1 左孩子結點 對 3 7 8 進行判斷,已符合最小堆規則 則不調整 break arr i tmp pos 開始迴圈調整 2位置的 while ...

堆排序實現

今天抽空寫了個堆排序的演算法,廢話不多說,直接上源 include include includeusing namespace std define maxsize 6 void print int a,int size maxsize void percolate up int a,int si...

堆排序實現

1 堆排序演算法描述 1 定義 n個關鍵字序列kl,k2,kn稱為 heap 當且僅當該序列滿足如下性質 簡稱為堆性質 1 ki k 2i 且ki k 2i 1 1 i n 2 當然,這是小根堆,大根堆則換成 號。k i 相當於 二叉樹的非 葉子結點,k 2i 則是左子節點,k 2i 1 是右子節點...