深入理解heap

binary heap

binary heap是一种complete binary tree(完全二叉树),也就是说,整棵binary tree除了最底层的叶节点之外,是填满的,而最底层的叶节点由左到右又不得有空隙,如图所示:

在这里插入图片描述
complete binary tree整棵树内没有任何节点漏洞,这带来一个极大的好处:我们可以利用array来存储所有节点,假设动用一个小技巧,将array的#0元素保留,那么当complete binary tree中的某个节点位于array的i处时,其左节点必位于array的2i处,其右节点必位于array的2i+1处,其父节点必位于i/2处(此处的"/‘’权且代表高斯符号,取其整数),这种通过array表述tree的方式,我们称为隐式表述法
array的缺点是无法动态改变大小,以vector代替array是更好的选择
根据元素排列方式,heap可分为max—heap和min—heap两种,前者每个节点的键值都大于或等于其子节点键值,后者的每个节点键值都小于或等于其子节点键值

heap算法

push_heap算法

下图所示的是push_heap算法的实际操演情况,为了满足complete binary tree的条件,新加入的元素一定要放在最下一层作为叶节点,并填补在由左至右的第一个空格,也就是把新元素插入在底层vector的end()处
在这里插入图片描述
新元素是否适用于其现有位置?为满足max-heap的条件,我们执行一个所谓的percolate up(上溯)程序,将新节点拿来与其父节点比较,如果其键值比父节点大,就父子对换位置,如此一直上溯,直到不需对换或直到根结点为止
下面是算法的实现细节:

template<class RandomAccessIterator,class Distance,class T>
void _push_heap(RandomAccessIterator first,Distance holeIndex,Distance topIndex,T value)
{
	Distance parent=(holdIndex-1)/2;//找出父节点
	while(holeIndex>topIndex&&*(first+parent)<value)
	{
		//当尚未到达顶端,且父节点小于新值
		//由于以上使用operator<.可知STL heap是一种max-heap
		*(first+holeIndex)=*(first+parent);//令洞值为父值
		holeIndex=parent;//调整洞号,向上提升至父节点
		parent=(holeIndex-1)/2;//新洞的父节点
	}//持续至顶端,或满足heap的次序特性为止
	*(first+holdIndex)=value;//令洞值为新值,完成插入操作
}

pop_heap算法

如图所示:
在这里插入图片描述
下面是pop_heap算法的实现细节

template<class RandomAccessIterator,class Distance,class T>
void _adjust_heap(RandomAccessIterator first,Distance holeIndex,Distance len,T value)
{
	Distance topIndex=holeIndex;
	Distance secondChild=2*holeIndex+2;
	while(secondChild<len)
	{
		//比较洞节点之左右两个子值,然后以secondChild代表大子节点
		if(*(first+secondChild)<*(first+(secondChild-1)))
			secondChild--;
		//令较大子值为洞值,再令洞号下移至较大子节点处
		*(first+holeIndex)=*(first+secondChild);
		holeIndex=secondChild;
		//找出新洞节点的右子节点
		secondChild=2*(secondChild+1);
	}
	if(secondChild==len)//没有右节点,只有左节点
	{
		*(first+holeIndex)=*(first+(secondChild-1));
		holeIndex=secondChild-1;
	}
	//将欲调整值填入目前的洞号内,注意,此时肯定满足次序特性
	_push_heap(first,holeIndex,topIndex,value);
}

注意,pop_heap之后,最大元素只是被置放于底部容器的最尾端,尚未被取走,如果要取其值,可使用底部容器(vector)所提供的back()操作函数,如果要移除它,可使用底部容器所提供的pop_back()的操作函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值