1.針對的問題:很快的找出最大的元素(最大堆)、很快的找出最小的元素(最小堆)
它不適用於從一堆數中檢索某一個數
如何去定義一個堆?抓住兩點:
完全二叉樹、任何一個內部結點的值大於等於其子節點的值
一個堆一定是完全二叉樹的形式:節約空間、可以很方便的用數組表示
最大堆:根大於等於任何一個子節點(堆排序)
最小堆:根小於等於任何一個子節點(Krustral)
2.關鍵操作:shiftdown 和 buildHeap
如何根據已知的元素建立一個堆?
核心思想:(以最大堆爲例)假設左子樹與右子樹已經是堆了,如果根的值比左右節點的值都大,則不做任 何改變。否則,選取左右子樹中較大的那一個與根交換位置,然後一直shiftdown下去,直到當前已經是葉節點或已經在正確的位 置。
核心代碼:
void shiftDown(int pos)//從 pos開始shiftdown
{
while (!isLeaf(pos))
{
int m = 2 * pos + 1, r = 2 * pos + 2;
if (r<n&&heap[r]>heap[m])
m = r;
if (heap[pos] >= heap[m])return;
else swap(heap, pos, m);
pos = m;
}
}
void buildHeap()
{
for (int i = n / 2 - 1; i >= 0; i--)
shiftDown(i);
}
如何在已經建好的堆中插入一個元素?
核心思想:每次把元素放到數組最後的位置,與父節點比較,如果它的值比父節點的值要大,則與父節點交換位置(shiftup)
一直shiftup下去,直到已經是根節點或已經在正確的位置
void insert(const int& it)
{
if (n < maxsize)
{
int curr = n++;
heap[curr] = it;
while (curr != 0 && heap[curr] > heap[parent(curr)])
{
swap(heap, curr, parent(curr));
curr = parent(curr);
}
}
}