演算法與資料結構 六 堆排序

2022-06-24 19:03:08 字數 1650 閱讀 6232

上一次說到了3種基本的排序演算法,三種基本的排序演算法時間複雜度都是o(n^2),雖然比較簡單,但是效率相對較差,因此後續有許多相應的改進演算法,這次主要說說堆排序演算法。

堆排序演算法是對選擇排序的一種優化。

那麼什麼是堆呢?堆是一種樹形結構。在維基百科上的定義是這樣的「給定堆中任意節點 p 和 c,若 p 是 c 的母節點,那麼 p 的值會小於等於(或大於等於) c 的值」。

這句話通俗一點就是,樹的根節點需要大於(小於)它的孩子節點,而每個左右子樹都滿足這個條件。當樹的根節點大於它的左右孩子節點時稱為大頂推,否則稱為小頂堆。

排序演算法的思路是這樣的,首先將序列中的元素組織成乙個大頂堆,將樹的根節點放到序列的最後面,然後將剩餘的元素再組織成乙個大頂堆,然後放到倒數第二個位置,以此類推。

先假定它們的對應關係如下圖所示:

我們從樹的最後乙個非葉子節點開始,從這個子樹中選擇最大的乙個數,將它交換到子樹的根節點,也就是如下圖所示

接著再從後往前查詢下乙個非葉子節點

經過這樣一輪,一直調整到樹的根節點,讓後將根節點放到序列的最後乙個元素,接著再將剩餘元素重新組織為乙個新的堆,直到所有元素都完成排序

現在已經對堆排序的基本思路有了一定的了解,在寫**之前需要建立樹節點與它在序列中的相關位置做乙個對應關係,假設乙個非葉子節點在序列中的位置為n,那麼它的兩個子節點分別是2n + 1與 2n + 2。而且小於n的一定是位於n前方的非葉子節點,所以在調整堆時,從n開始一直到0,前面的一定是非葉子節點,根據這點可以寫出這樣的**

void heapsort(int a, int nlength)

for (int n = nlength - 1; n > 0; n--)

上述**首先取最後乙個葉子節點,對所有非葉子節點進行調整,得到堆頂的最大元素。然後將最大元素與序列最後乙個做交換,接著使用迴圈,對序列中剩餘元素進行同樣的操作。

調整堆時,首先比較子樹的根節點與它下面的所有子節點,並儲存最大數的位置,然後將最大數與根節點的數進行交換,這樣一直進行,直到完成了堆根節點的交換。

void heapadjust(int a, int nidx, int nlength)

if (a[nidx] < a[child])

else

//如果進行了交換,為了防止對子節點對應子樹的破壞,要對子樹也進行調整

nidx = child;

}}

從演算法上來看,它迴圈的次數與堆的深度有關,而二叉樹的深度應該是log2(n) 向下取整,所以調整的時候需要進行log2(n)次調整,而外層需要從0一直到n - 1的位置每次都需要重組堆並進行調整,所以它的時間複雜度應該為o(nlogn), 它在效率上比選擇排序要高,它的速度主要體現在每次查詢選擇最大的數這個方面。

資料結構之排序(六) 堆排序

堆是具有下列性質的完全二叉樹 每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆,如左圖 或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆,如右圖。堆排序 heap sort 就是利用堆 假設利用大頂堆 進行排序的方法。它的基本思想是,將帶排序的序列構造成乙個大頂堆。此時,整個序列的最...

資料結構 堆與堆排序

堆其實是從完全二叉樹演變過來的並且用來儲存資料的,什麼是完全二叉樹呢?完全二叉樹就是 若設二叉樹的深度為h,除第h層外,其它各層 1 h 1 的結點數都達到最大個數,第h層所有的結點都連續集中 在最左邊,這就是完全二叉樹。我們知道二叉樹可以用陣列模擬,堆自然也可以。現在讓我們來畫一棵完全二叉樹 從圖...

堆資料結構與堆排序

堆資料結構 堆 二叉堆 是近似的完全二叉樹,最底層允許不滿,堆的相關,陣列長度length,heap size有效長度 堆的有效元素,未排序的數目 heap size堆雖然很像二叉樹,但是我的理解就是用二叉樹的邏輯,但是最主要的區別在,堆的儲存是用陣列,只是用下標來幫助理解 堆的儲存結構 從上往下,...