1.1 堆的定義與基本操作
堆是一顆完全二叉樹,數中每個結點的值都不小於(或不大於)其左右孩子的結點的值。其中,如果父親結點的值大於等於孩子結點的值,那麼稱這樣的堆為大頂堆,這時每個結點的值都是以它為根結點的子數的最大值;如果父親結點的值小於等於孩子結點的值,那麼稱這樣的堆為小頂堆,這時每個結點的值都是以它為根結點的子數的最小值。堆一般用於優先佇列的實現,而優先佇列預設使用大頂堆,因此我以大頂堆為例來講述,以下所指的堆都是指大頂堆。
好,那怎麼具體實現呢?對於完全二叉樹來說,比較簡單的是實現方法是用陣列來儲存完全二叉樹。這樣結點就按層序儲存於陣列中,其中第乙個結點將儲存於陣列中的1號位,,並且陣列i號位表示的結點的左孩子就是2i號位,而右孩子是(2i+1)號位。於是可以像下面這樣定義陣列來表示堆:
const
int maxn =10;
int heap[maxn]
, n =
10;
而建堆過程事實上是向下調整:,調整方法如下:
總是將當前結點v與它們的左右孩子比較(如果有的話),假如孩子中存在權值比結點v的權值大的,就將其中權值最大的那個孩子結點與結點v交換;交換完畢後繼續讓結點和其左孩子比較,直到結點v的的孩子的權值都比結點的權值小或是結點v不存在孩子結點。
可以寫出向下調整的**:
//對heap陣列在[low,high]範圍內進行向下調整
//其中low為欲調整結點的陣列下標 high一般為堆的最後乙個元素陣列的下標
void
downadjust
(int low,
int high)
//如果孩子中最大的權值比欲調整的結點i大
if(heap[j]
>heap[i]
)else
}}
建堆的**如下:
//建堆 o(n)
void
createheap()
}
另外,如果要刪除堆中的最大元素(也就是堆頂元素),並讓其保持堆的結構,那麼只需要最後乙個元素覆蓋堆頂元素,然後對根結點進行調整即可。
//刪除堆頂元素 o(logn)
void
deletetop()
那麼,如果要往堆裡新增乙個元素,應當怎麼辦呢?可以把想要新增的元素放在陣列最後(也就是完全二叉樹的最後乙個結點後面),然後進行向上調整操作。向上調整就是把欲調整結點與父親結點比較,如果權值比父親結點大,那麼就交換其與父親結點,這樣反覆比較,直到達到堆頂或是父親結點的權值較大為止。
//往堆裡新增乙個元素
//對heap陣列在[low,high]範圍進行向上調整
//和向下調整思路差不多 就是j的賦值有所改變
//其中low一般設定為1 high表示欲調整結點的陣列下標
void
upadjust()
else
//父親權值比欲調整結點i的權值大 調整結束
}}
堆排序是指使用堆結構對乙個序列進行排序。此處討論遞增排序的情況。考慮對乙個堆來說,堆頂元素是最大的,因此在堆建立完畢後,堆排序的直觀思路就是取出堆頂元素,然後將堆的最後乙個元素替換至堆頂,再進行依次針對堆頂元素的向下調整-----如此重複,直到堆中只有乙個元素為止。
具體實現時,為了節省空間,可以倒著遍歷陣列,假設當前訪問到i號位,那麼將堆頂元素與i號位的元素交換,接著在[1,i-1]範圍內對堆頂元素進行一次向下調整即可。
//堆排序
void
heapsort()
}
堆及其應用(優先順序佇列,TopK問題,堆排序)
完整 首先建立乙個無序完全二叉樹序列,然後自底向上調整每乙個非葉結點。調整規則是將調整結點值變為比左右孩子結點都小 小根堆 若不滿足,迴圈調整到樹下層,稱為向下調整。為什麼從最後的非葉結點向前調整?因為每次調整起碼要保證當前結點比左右子樹結點都小,而如果從跟結點開始調整只能保證跟結點比左右孩子值小。...
堆的應用 優先順序佇列
標頭檔案 pragma once ifndef heap h define heap h typedef int datatype typedef int compare datatype left,datatype right typedef struct heap heap void creat...
堆與優先順序佇列
本篇文章主要基於演算法algorithm第四版 背景 處理有序元素時,不一定要求所有資料有序,只要求處理當前最大 優先順序最高 的元素 優先順序佇列 支援 刪除最大元素 和 插入元素 兩種操作的一種資料結構 優先順序佇列的基本實現可以使用 有序 或 無序 的陣列和鍊錶 基於陣列或鍊錶的操作最壞情況下...