Leftist Heaps

问题背景

如果使用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. Leftist Heaps是一种便于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、从后向前,把最后一个树作为倒数第二个树的左子树,检查倒数第二个树左右子树NPL是否满足要求,若不满足,把倒数第二个树左右子树交换。

(可以用栈实现,如果降序排列的话就可以用堆实现)


其他建立在合并操作上的操作:

插入看做是原倾堆和一个节点的左倾堆的合并。

删除看做是删除根节点,将剩余的左右子堆合并。(复习:堆的删除操作特指删除根节点,即得到优先级最高的元素)


Leftist Heaps总体思想

1. Leftist Heaps通过不平衡的节点分布,让right path保持较短状态,把合并操作建立在对right path操作上,提高合并效率。

2. 在合并过程中,通过左右子树互换来保持”左倾“的性质。



Reference

纸上谈兵: 左倾堆 (leftist heap)

左堆(Leftist Heaps)(举例图解很清楚明白)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值