Leftist Heaps
2016-03-30 11:06
148 查看
问题背景
如果使用original heaps的数据结构,合并两个堆需要Θ(n)的时间,等同于建立一个新的堆的时间,并且拷贝操作需要额外的空间。我们可以用Leftist Heaps实现时间复杂度为O(n)的更有效率的合并。
NPL的引入
1. 定义:null path length,该节点到一个没有两个儿子的节点的最短路径的长度。规定NPL(NULL)=-1。2. 推论:NPL(X)= min(NPL(X的儿子))+1(对任意节点包括没有两个儿子的节点成立)。
Leftist Heaps定义
满足original heaps优先级要求(即每个节点的优先级大于它的所有子节点的优先级),并且每一个节点左子树NPL值不小于右子树的NPL值。Leftist Heaps特点
1. LeftistHeaps是一种便于merge的数据结构。
2.Leftist Heaps是一种不平衡的数据结构。
3. Leftist Heaps不仅要存储节点元素值,还要存储NPL,不再能用数组实现。
4. Leftist
Heaps的任意子树也是Leftist Heaps(从定义可知)。
5. Leftist
Heaps的right path(右侧路径)上节点数不大于任何路径上的节点数(right path是从根节点开始,不断前往右子节点构成的路径)。
6.
如果一个Leftist Heap的right
path上有r个节点,那么该Leftist Heap至少有2^r-1个节点(数学归纳可以证明)。也就是说如果一个Leftist
Heap有N个节点,那么该Leftist Heap的右侧路径至多有log(N+1)个节点。对right
path进行操作,时间复杂度是O(logN)。
Leftist
Heaps的merge操作(重点)
时间复杂度:O(logN)。递归实现的步骤如下:(实际C语言实现中分为合并的驱动函数和合并的实际操作函数,具体见后面的实现)
1. 如果一个空左倾堆和一个非空左倾堆合并,返回非空左倾堆(递归中的base
case)。
2. 如果两个左倾堆都非空,那么比较两个根节点。取较小的节点为新的根节点(为了符合堆的优先级要求),合并较小根节点堆的右子堆和较大根节点堆。
3. 如果右子堆NPL大于左子堆NPL,交换右子堆和左子堆。
4. 更新根节点的NPL=右子堆NPL+1。
非递归实现的步骤如下:
1、把所有节点的右子树分离出来。
2、把分离出来的子树按根节点元素升序(广义上的升序)排列。
3、从后向前,把最
932c
后一个树作为倒数第二个树的左子树,检查倒数第二个树左右子树NPL是否满足要求,若不满足,把倒数第二个树左右子树交换。
(可以用栈实现,如果降序排列的话就可以用堆实现)
其他建立在合并操作上的操作:
插入看做是原倾堆和一个节点的左倾堆的合并。
删除看做是删除根节点,将剩余的左右子堆合并。(复习:堆的删除操作特指删除根节点,即得到优先级最高的元素)
Leftist Heaps总体思想
1. Leftist Heaps通过不平衡的节点分布,让rightpath保持较短状态,把合并操作建立在对right path操作上,提高合并效率。
2.
在合并过程中,通过左右子树互换来保持”左倾“的性质。
Reference
纸上谈兵: 左倾堆 (leftist heap)左堆(Leftist Heaps)(举例图解很清楚明白)
相关文章推荐
- PHP中define和defined的区别
- 沉浸式状态栏
- 【Poj 1260】 Pearls dp
- xmlSchema 1.0 - 1.4 各个版本免费下载
- LINUX qt程序控制台程序编译成功无法运行提示cannot change to directory.....
- sql执行顺序和分组函数
- 处理器体系架构
- jQuery(四)(DOM一)
- cocos2d-x避免手动修改android.mk文件来编译
- 算法训练 安慰奶牛
- Spring MVC 注解方式 静态类 注入bean
- Android 应用(中英文)切换
- 1.Nginx的基本特性及编译安装
- 当存储无可用空间时无法启动虚拟机
- Study jams 第二课程的学习
- Python——Pandas
- Fragment上的上下左右滑动onFling的手势识别
- 动态端口范围
- 创建、输出单链表
- 100天JAVA学习计划03-浅谈方法