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);
}
}
}