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

2021-09-23 20:43:51 字數 1931 閱讀 1808

堆的應用

優先佇列的主要操作:

例子:在n個元素中選出前m個元素?(比如,在100萬個元素中選出前100名)

排序,nlogn

優先佇列,nlogm(維護乙個容量為m的最小堆,遍歷完100萬個陣列之後,形成的最小堆中的m個元素就是最小的)

總共n個請求,使用普通陣列或者順序陣列,最差情況o(n^2)

使用堆,o(nlogn)

最大堆兩個特點:

二叉樹上任何乙個節點都不大於其父節點,(並不能說明,層數越高,值就越大)

是一顆完全二叉樹。除了最後一層外,其他層的節點數必須是最大值,最後一層,節點數雖然可以不是最大值,但是所有節點必須集中在左側,

用陣列儲存二叉堆,

節點規律:

步驟:將元素插入二叉堆的最底層,

shiftup調整,將插入元素與其父節點比較,一步步向上轉換**換規則:如果該節點比其父節點還大,就往上換)

步驟:把根節點彈出來,把最底下的元素拿出來放入根節點,

shiftdown調整,將根節點元素一步步向下轉換**換規則:比較左右孩子的大小,如果根節點比最大的子孩子還大,則將其與最大的孩子換位置)

可以借助二叉堆來實現,思路是:

將任意陣列依次insert到最大堆o(logn)(也可以使用heapify操作,將陣列形成最大堆,複雜度o(n))

再從最大堆中依次彈出,就能得到排好序的降序序列;

(想要得到公升序序列,利用最小堆即可)

這是乙個將給定陣列,形成最大堆的方法,

將n個元素逐個插入到乙個空堆中,複雜度是o(nlogn),而heapify過程,複雜度只有o(n)。

具體操作是:

將元素順序塞入最大堆中去,

對於所有的葉子節點,本身就是乙個最大堆,不用進行處理;從第乙個不是葉子節點的節點(從n/2的位置開始,逆序降到1) 開始, 逐級向上處理,將葉子節點的父節點當做乙個最大堆,這時候只需執行shiftdown操作,將小的根節點往下轉換,一直遞迴到最底層結束。

【分析】:

將n個元素逐個插入到乙個空堆中,演算法複雜度是o(nlogn),

步驟: 拿出最大堆頂端的最大值,與最後乙個元素交換,最大元素已經歸位,count–,拿出此時的頂端值,使用shiftdown調整頂端值,使得剩餘元素依然是乙個最大堆,繼續拿出頂端的最大值,與最後乙個元素交換,使用shiftdown調整,依次類推。

對於這個二叉堆的節點編號(根節點為0號),父節點與子節點的關係為:

parent(i) = (i -1) /2

left child(i) = 2 * i + 1

right chid(i) = 2 * i + 2

在堆中存放的是索引,陣列本身沒有發生改變。比較大小的時候,比較的是data資料,但是構建索引堆的時候,堆中存放的是data資料對應的下標。元素交換的時候,也只是交換索引即可。

構造reverse陣列,reverse陣列中存放的是陣列的下標在indexes中的位置。

使之與indexes陣列互為逆序,即indexes[i] = j , reverse[j] = i

indexes[reverse[i]]=ireverse[i]本身的定義就是表示索引i在indexes中的位置,因此indexes[reverse[i]]=i

reverse[indexes[i]] = iindexes[i]表示i這個位置的索引是誰,reverse表示這個索引在indexes中的位置,

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

堆結構 就是一顆完全二叉樹,二叉樹是不存在的,可以腦補,真正實現堆結構的是陣列 葉節點 沒有左右孩子的節點 滿二叉樹 最後一層都是葉節點,並且填滿最後一層 完全二叉樹 滿二叉樹屬於完全二叉樹,滿二叉樹從右往左依次去葉節點形成的樹就是完全二叉樹 陣列下標位置為i,在不越界的情況下 2 i 1是i位置數...

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

堆排序 先用n個待排序的元素來初始化乙個大根堆,然後從堆中逐個提取元素 刪除 每次都取堆頂的元素,將其放在序列最後面,然後將剩餘的元素重新調整為最大堆,依次類推,最終得到排序的序列。結果這些元素按照非遞增的順序排列。初始化時間為o n 每次刪除的時間為o logn 因此總時間為o nlogn inc...

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

這是我最近幾天寫排序的最後乙個演算法排序了 我覺得這個堆排序和歸併排序可以說是這幾個演算法中寫起來最困難的 了。堆排序 是指利用堆這種資料結構所設計的一種排序演算法。因為堆是乙個近似完全二叉樹的結構,並同時滿足堆積的性質 即子結點的鍵值或索引總是小於 或者大於 它的父節點,所以建堆就和建樹一樣,必須...