简述
对于堆,我个人的理解就是一种优先队列,从队列中取元素的时候总是取出最大(或最小)的元素。二叉堆是一种堆的一种实现形式,是一棵完全二叉树。对于二叉堆,我们显然可以分成两类:大根堆和小根堆,表示他每次取出的是最大元素还是最小元素。而大根堆一定是满足这样的一个性质,即:对于任意一个节点,他一定不大于他的父亲,而且不小于他的两个儿子。小根堆反之。
实现功能
以$O(n)$的时间建树,并以$O(logn)$的复杂度实现插入、寻找最小(或最大)值,修改元素,删除元素。
实现思路(小根堆)
我们用一个数组来储存数据,下标从1开始,对于第$i$个元素,他的左儿子为$i2$,他的右儿子为$i2+1$,当然对于非根节点,他的父亲就是$i/2$。在这里,这个数组用$heap[]$表示。
同时,我们用数组$id[i]$数组来表示第(i)个元素是第几个插入的,用$pos[i]$来表示第$i$个元素是第几个插入的(很明显有$id[pos[i]]=i$)。当然,根据实际情况,这两个东西可以不要。
这里要用到的最重要的两个函数是$up(i)$和$down(i)$函数, $up(i)$函数是将第$i$个元素上移,如果他比他的父亲大,就和他的父亲交换位置,即维护他比他父亲小的性质。$down(i)$函数类似,只是比较的是两个儿子中较小的那个。
接下来是算法的核心:
- 当加入一个元素时,我们把他加入到堆的底部,即heap数组的末尾,然后调用$up(i)$函数将其上移到合适位置。
- 当修改一个元素时,只要直接修改,然后分别调用$down(i)$函数和$up(i)$函数找到他适合的位置。
- 当删除堆顶元素的时候,我们只要把他和最后一个元素交换位置(这样只需要将数组大小减一就可以删掉他),然后用$down(i)$函数将堆顶元素下移到合适位置。
- 当删除任意元素时,只需要把他赋值为负无穷,然后上浮到堆顶,再利用删除堆顶元素的方法删除他。
基本模版
1 |
|