其他堆的操作

由于对于最小堆来说(即上文介绍的堆),其堆序性质是要求父节点必须小于子节点。则在最小堆寻找最大的元素必然会遍历整个堆。同时,如果想要找到特定的某个元素,必须对整个堆进行搜索。同时,要知道元素在所有数据中所处的位置,就需要通过其他的数据结构来进行实现。因为堆所具有的两个性质:结构性(完全二叉树)和堆序性并不能保证能确定元素的位置。

线性搜索整个数组,则需要的时间为O(n), 在元素过多的时候会浪费大量的时间,因此有了以下方法(或者说是函数)来降低运行时间以达到O(log N)的结果。

一、DecreaseKey (降低关键字的值)和IncreaseKey(提高关键字的值)

DecreaseKey(P,Δ,H)人工降低在位置P处的关键字的值,降值幅度为Δ。IncreaseKey(P,,Δ,H)则增加。

在降低或增加后,可能会破坏堆的堆序性质,那么则应该通过上滤和下滤进行调整。其中,上滤和下滤分别在Insert和DeleteMin函数中用过。其大致方法就是使用一个Tmp,比较父子关键字的值的大小并在父节点大于子节点的值时进行交换。

以下为函数实现(上下渗)

void PercolateUp(int P, PriorityQueue H)
{
	int i;
	ElementType X = H->Element[P];
	for (i = P; P / 2 != 0 && H->Element[i] <= H->Element[i / 2]; i /= 2)
		H->Element[i] = H->Element[i / 2];
	H->Element[i] = X;
}

void PercolateDown(int P, PriorityQueue H)
{
	int i;
	ElementType Tmp;
	for (i = P; i * 2 <= H->Size && H->Element[i] >= H->Element[i * 2]; i *= 2)
	{
		Tmp = H->Element[i * 2];
		H->Element[i * 2] = H->Element[i];
		H->Element[i] = Tmp;
	}
}

二、Delete(删除)

Delete(P,H)函数删除位于位置P处的节点。实现是通过DecreaseKey(P,Δ,H)将P处的关键字降到一个本不可能存在的值,然后通过DeleteMin函数删除,应该注意到的是DeleteMin函数已经用到了下渗。

三、BuildHeap(构建堆)

BuildHeap(H)操作把N个关键字作为输出Insert到一个空的堆里。由于每次Insert所耗费时间为O(1)(平均),则N次连续的操作则耗费O(N)。或者直接按顺序插入到数列中,并对所有父节点执行下渗操作。与前者相比,后者更能维持堆的结构特性。

 

 

 

 

 

d-堆

d-堆与二叉堆的关系类似B树与二叉树的关系。二叉堆的父亲都有两个儿子,而d-堆中的父亲则有d个儿子。因此,存储同样数量的元素数据,在d>2的情况下,d-堆的深度应该比二叉堆浅。因此Insert的最坏运行时间也就变为了log(k)N。然而DeleteMin所用的时间则会提高,因为儿子的数量多了,在儿子中寻找最大的儿子所需要的时间就变多了。同时,与二叉堆相同,d-堆也不能进行Find操作和Merge操作。(对于Find例程,与其说不能,不如说所消耗的时间与以普通的数组形式存储数组所消耗的时间相同)。

左式堆(leftist heap)

由于二叉堆不能进行Merge操作(消耗的时间为Θ(N),与Find操作相同,所消耗的时间与以普通的数据结构的形式存储时进行Merge消耗的时间相同),人们发明了具有与二叉堆具有的结构特性-完全二叉树不同,甚至说截然相反的结构特性的数据结构-左式堆。

1、性质。

在介绍左式堆性质之前,我们先引入零路径长(Null Path Length,NPL)的概念。函数Npl(X)定义为从X到没有两个儿子的节点的最短的路径长。同时将具有0个或者1个儿子的Npl定义为0,空节点(NULL)的Npl定义为-1。

因此,显然的,零路径长试图找到距离该节点最短存在空节点的地方。进一步,对于一个堆来说,任意节点的零路径长比其儿子中最小的零路径长多1。

 

左式堆的性质与零路径长有关:对于堆中的每一个节点X,左儿子的零路径长不小于右儿子的零路径长,直观地来讲,左儿子所具有的树的深度比右儿子深。同时,还具有:对于任意一个堆中的节点,右路径(即一直向右走)是所有零路径中最小的。

同时还具有定理:在右路径上有r个节点的左式堆至少有2^r-1个节点。

 

关于左式堆的操作将在下一篇文章更新。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值