1 定义
堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。由此可见,堆是树与向量的结合体,其逻辑结构等同于完全二叉树,而物理结构与向量相同。
二叉堆具有结构性和堆序性,所谓结构性即其逻辑结构等同于完全二叉树,而堆序性则是堆中任一节点都与其父节点有固定的大小关系。
二叉堆可分为大顶堆和小顶堆,大顶堆的父结点的键值总是大于或等于任何一个子节点的键值;小顶堆父结点的键值总是小于或等于任何一个子节点的键值。
2 插入
2.1 插入策略
将新词条插入向量末尾,新词条的引入并未破坏堆的结构性,但有可能破坏了堆序性,需要进行上滤操作恢复堆序性,即将新词条与父节点词条交换位置,重复此操作直至堆序性恢复。
2.2 实例分析
(a)一个完全二叉堆
(b)插入新词条5至末尾,不满足堆序性,5上滤
(c)不满足堆序性,5上滤
(d)满足堆序性,插入完成
2.3 插入效率
插入向量末尾消耗时间O(1),插入操作的主要时间消耗为上滤操作,上滤至多进行logn次,所以插入操作可以O(logn)时间内完成。
3 删除
3.1 删除策略
二叉堆的运用就是获取堆顶词条,所以待删除词条总是位于堆顶。调用向量接口删除堆顶后,堆的结构性将被破坏。为修复这一缺陷,将最末尾的词条转移至堆顶。此时堆的结构性恢复,但堆序性遭到破坏。
由于新堆顶不满足堆序性,进行下滤操作,即将新词条与两个孩子中的最大者交换位置,重复此操作直至恢复堆序性。
3.2 实例分析
(a)一个完全二叉堆
(b)删除最大值5,并将末尾词条1转至堆顶
(c)不满足堆序性,词条1下溢
(d)不满足堆序性,词条1下溢
3.3 删除效率
删除与插入类似,下溢操作至多进行logn次,所以时间复杂度为O(logn)
4 建堆
4.1 蛮力算法
反复调用插入接口,即可将输入词条逐一插入其中,并最终完成建堆任务。但该方法的效率过低,若有n个词条,则共需迭代n次,第k轮迭代耗时O(logk),故累计耗时为:
O(log1 + log2 + … + logn) = O(logn!) = O(nlogn)
在高效排序算法的帮助下,本可以O(nlogn)时间内完成一次全排序,而在这里花费同样多时间所生产的堆却只能提供一个偏序。这一事实在某种程度上也暗示着,或许存在某种更快的建堆算法。
4.2 Floyd算法
可以将暴力法理解为自下而上的上滤,而Floyd则是从下而上的下滤。只需自下而上地遍历所有内部节点,并对每个内部节点分别调用一次下滤算法。
该算法依然需做n步迭代,以对所有节点各做一次下滤。这里,每个节点的下滤所需的时间线性正比于其高度,故总体运行时间取决于各点的高度总和:
Σhi=0( (d-i)·2i ) = 2d+1 - (d+2) = n - log2(n+1) = O(n)
由于在遍历所有词条之前,绝不可能确定堆的结构,故以上已是建堆操作的最优算法。
该文内容均来自邓俊辉老师的《数据结构与算法》