堆
C语言的堆区与栈区
数据结构中的最大二叉堆:
如图所示,它是一颗完全的二叉树,除了最后一层外都是填满的,堆的子女和父母的关系可以利用上标计算。
关于最大二叉堆的操作,有保持堆性质MAX-HEAPIFY,建立堆BUILD-MAX-HEAP过程。若需要使用二叉堆进行堆排序,则需要HEAP-EXTRA-MAX等。
堆保持的递归算法如下:
通过比较元素与左右子女的大小,判断有没有保持堆的要求。
下图为堆排序示例:
建立堆的过程如下:
堆排序过程如图:
高效的优先级队列使用二叉堆进行实现,如下为利用最大堆实现的最大优先级队列
优先级队列一般支持四项操作:1.插入;2.返回最大值(即取队首元素);3.返回并去掉最大值;4.将某x元素增大到k。
通过观察二叉堆,不难实现以上操作。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
从二叉堆说到二项堆及斐波那契堆
二叉堆(binary heap)
二项堆(binomial heap):
二项堆是满足下列性质的二项树构成:
- 二项树遵循最小堆原理(节点的关键字大于或者等于其父节点)。
- 对于任意非负整数k,在H中至少有一棵二项树的根具有度数k。
二项堆中的二项树的深度与节点的关系恰好符合组合,即二项式的系数。
先介绍下二项树:
二项树有如下性质:
- 若有二项树Bk,其节点为2k个。
- 树的高度为k
- 深度i处恰好有组合个节点
- 根的度数为k,大于其他节点。并且根的子女从左到右分别是k-1,k-2…..0。
对于一个二项树有如下结构
按照后续遍历获得的顺序
二项堆的表示:
二项堆的主要操作:
- 寻找最小关键字
最小关键字均在根节点,故其最多为⌊lg n⌋ + 1
- 合并两个堆
- 插入节点
构造一个单节点的树,然后合并两棵二项树 - 抽取最小关键字
一个二项堆H,具有最小关键字的X被去掉,X子女逆转,然后合并 - 减小关键字的值
- 删除关键字
暂时略
然后是斐波那契堆(Fibonacci Heaps)
相对于二项堆,斐波那契堆在不涉及删除元素的操作时,仅需要O(1)的平摊时间。
Fibonacci Heap在EXRTRACT-MIN和DELETE操作的数目较小。
在最小生成树和寻找单源最短路径时对每一条边会调用DECREASE-KEY,即利用优先级队列,
其O(1)的平摊时间对于O(lgn)来说提升很大。但是斐堆不如二叉堆来得实用。
斐波那契堆由一组最小堆有序树组成,但是堆中的树不一定是二项树。
此堆中的树都是有根而无序的
主要操作:
- 插入一个节点
- 抽取最小值
- 减小关键字
关于可合并堆的总结:
可合并堆支持的7种操作:
- 创建新堆
- 插入元素x
- 返回堆中最小或者最大的元素
- 删除最小或者最大元素
- 合并两个堆
- 将关键字值k赋予堆中节点
- 删除堆中结点
若不需要合并操作,那二叉堆已经很符合要求,二叉堆的合并操作最坏运行时间为O(n),二项堆和斐波那契堆的合并就相对较快。
在Prim算法中,性能取决于队列Q的实现,若用二项堆来实现Q,
BUILD-MIN-HEAP初始化为O(V)
EXTRACT-MIN需要O(lgV)次,运行V次,所以时间为O(VlgV)
还有E次DECREASE-KEY操作,单次为O(lgV)
所以总的时间O(VlgV + ElgV) = O(ElgV)
若使用斐波那契堆,时间可以减少到O(E+VlgV)