基本性质
优先级队列,也叫二叉堆、堆(不要和内存中的堆区搞混了,不是一个东西,一个是内存区域,一个是数据结构)。
堆的本质上是一种完全二叉树,分为:
最小堆(小根堆):树中每个非叶子结点都不大于其左右孩子结点的值,也就是根节点最小的堆,图(a)。
最大堆(大根堆):树中每个非叶子结点都不小于其左右孩子结点的值,也就是根节点最大的堆,图(b)。
基本操作
均以大根堆为例
存储方式
堆本质上是一颗完全二叉树,使用数组进行存储,从\(a[1]\)开始存储,这样对于下标为\(k\)的结点\(a[k]\)来说,其左孩子的下标为\(2*k\),右孩子的下标为\(2*k+1\)。,且不论 \(k\) 是奇数还是偶数,其父亲结点(如果有的话)就是 $\left \lfloor k/2 \right \rfloor $。
向上调整
假如我们向一个堆中插入一个元素,要使其仍然保持堆的结构。应该怎么办呢?
可以把想要添加的元素放在数组的最后,也就是完全二叉树的最后一个结点的后面,然后进行向上调整(heapinsert)。向上调整总是把欲调整结点与父亲结点比较,如果权值比父亲结点大,那么就交换其与父亲结点,反复比较,直到到达堆顶或父亲结点的值较大为止。向上调整示意图如下:
代码如下,时间复杂度为\(O(logn)\):
void heapinsert(int* arr, int n) {
int k = n;
//如果 K 结点有父节点,且比父节点的权值大
while (k > 1 &&