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()的操作函数