您的位置:首页 > 其它

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

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

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

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

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

Leftist Heaps总体思想

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

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

Reference

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

左堆(Leftist Heaps)(举例图解很清楚明白)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: