最小 大堆的操作及堆排序

2022-05-30 18:30:17 字數 2318 閱讀 4171

摘自:《啊哈演算法》

我們要用1, 2, 5, 12, 7, 17, 25, 19, 36, 99, 22, 28, 46, 92來建立最小堆,並且刪除最小的數,並增加乙個數23

如何建立這個堆:

//

建堆n = 0

;for (int i = 1; i <= m; i++)

我們還有更快的方法可以建立乙個堆

思路:直接把1, 2, 5, 12, 7, 17, 25, 19, 36, 99, 22, 28, 46, 92放入乙個完全二叉樹中,在這個二叉樹中,我們從最後乙個節點開始,依次判斷以這個節點為根的子樹是否符合最小堆的特性。如果所有的子樹都符合最小堆的特性,那麼整棵樹就是最小堆了。(注意完全二叉樹有乙個性質,最後乙個非葉子節點是第n/2個節點,從1數起而不是從0數起)

演算法:把n個元素建立乙個堆,首先我們可以將這n個節點以自頂向下,從左到右的方式從1到n編碼,可以將這n個節點轉換成一棵完全二叉樹。緊接著從最後乙個非葉節點(節點編號為n/2)開始到根節點(節點編號為1),逐個掃瞄所有的節點,根據需要將當前節點向下調整,直到以當前結點為根節點的子樹符合堆的特性。時間複雜度是o(n)

**如下:

void

create_heap()

}

建堆後是完全二叉樹,並且所有父節點都比子節點小

接下來,我們將堆頂刪除,把新增加的23放在堆頂。

顯然加了數後已經不符合最小堆的特性了,我們需要將新增加的數調整到合適的位置。

向下調整,將這個數與它的兩個兒子2和5比較,選擇較小的乙個與它交換

此時我們發現還是不滿足最小堆,於是繼續將23與它的兩個兒子中較小的乙個交換。

再交換

向下調整的**:

void shiftdown(int i)  

else

//如果它有右兒子,再對右兒子進行討論

if (i*2 + 1

<=n)

//如果發現最小的編號不是自己,說明子結點中有比父節點更小的

if (t !=i)

else}}

如果只是想新增乙個數,而不是刪除最小值,只需要將新元素插入到末尾,再根據情況判斷新元素是否需要上移,直到滿足新的特性位置。

加入我們現在要加入乙個3

先將3與它的父節點25比較,發現比父節點小,需要與父節點交換。以此類推

向上調整的**:

//

新增加乙個元素

void shiftup(int i)

else

i = i/2

; }

}

堆排序:

時間複雜度是o(nlogn),假如要從小到大排序,那麼只需要建立最小堆,然後每次刪除頂部元素並將頂部元素輸出或者放入到乙個新的陣列中,直到堆為空為止。

int

deletemax()

一種更好的方法是,從小到大排序的時候不是建立最小堆而是建立最大堆,最大堆建立好後,最大的元素在h[1],因為我們的需求是從小到大排序,希望最大的放在最後,因此我們將h[1]和h[n]交換,此時h[n]就是陣列中的最大的元素。交換後將h[1]向下調整以保持堆的特性。

void

heapsort()

}

堆的其他應用:

1.求乙個數列中的第k大的數

建立乙個大小為k的最小堆,堆頂就是第k大的數

例如,假設有10個數,要求求第3大的數,第一步選取任意的3個數,比如說是前3個,將這3個數建成最小堆,然後從第4個數開始,與堆頂

的數比較,如果比堆頂的數要小,那麼這個數就不要,如果比堆頂的數大,則捨棄當前的堆頂而將這個數作為新的堆頂,並再去維護堆

最小 大堆的操作及堆排序

摘自 啊哈演算法 我們要用1,2,5,12,7,17,25,19,36,99,22,28,46,92來建立最小堆,並且刪除最小的數,並增加乙個數23 如何建立這個堆 建堆 n 0 for int i 1 i m i 我們還有更快的方法可以建立乙個堆 思路 直接把1,2,5,12,7,17,25,19...

最大堆 最小堆 堆排序

最 大 小堆的性質 1 是一顆完全二叉樹,遵循完全二叉樹的所有性質。2 父節點的鍵值 大於 小於等於子節點的鍵值 3 在堆排序中我們通常用的是最大堆,最小堆通常用在優先佇列中 尚未找到恰當的例子 堆排序 陣列 a 10 可以利用建堆的方式對其進行排序。因為堆是一顆完全二叉樹,根據完全二叉樹的性質可以...

最大堆的實現及堆排序

b站浙大資料結構課程 堆的原理與實現 堆排序演算法說明 最大堆,每個節點都比其左右子節點大。且是完全二叉樹。從根節點到任意節點路徑上結點序列的有序性。堆排序演算法說明 將待排序序列構建成乙個堆 h 0 n 1 根據 公升序降序需求 選擇大頂堆或小頂堆 把堆首 最大值 和堆尾互換 把堆的尺寸縮小 1,...