STL源码剖析学习八:heap & priority queue

STL源码剖析学习八:heap & priority queue


heap不是STL容器组件,但是作为priority queue的助手存在。

 

完全二叉树:整棵树除了最底层的叶节点之外,都是填满的,而最底层的叶节点从左至右不能有空隙。
好处是整棵树内没有任何节点漏洞,就可以用array表述整棵树(隐式表述法):将#0处保留,某个节点位于i处时,其左子节点必位于2i处,右子节点位于2i+1处,父节点位于2/i处。


为了满足动态改变容量的要求,用vector代替array。

 

push_heap:
先将新加入节点插在最底层最右边的位置,vector的end处
然后执行一个上溯的程序:把新节点与其父节点相比较,如果比它大就对换位置,直到到达根节点或者不需要对换为止。
在实现中vector的#0位置不保留,i的父节点为(i-1)/2

 

pop_heap
最大值在根节点,取走根节点(其实设置底部vector的尾端节点)
割舍最下层最右边的那个叶节点
执行下溯程序:将空节点和他较大的子节点对调位置,并且持续下放,直到到达叶节点位置,将之前被割舍的元素值赋给这个空洞节点,再对他进行一次上溯程序即可
pop_heap之后,最大元素只是被放置在底部容器的最尾端,尚未被取走,如果要取值,可以用vector的back操作,如果要移除可以用pop_back操作。

 

sort_heap
每次pop_heap都可以把最大值放到容器的最后,那么可以持续对容器进行pop_heap操作,并且每次操作范围从后向前减少一个元素,完成后就形成一个递增序列
排序过后,就不是一个合法的heap了。

 

make_heap
把现有的数据形成一个合法的heap
从后往前遍历,找到一个需要调整的子树的根节点,把较大的子节点和根节点互换
不断重复该过程,直到到达根节点。

关键函数__adjust_heap 调整堆

void __adjust_heap(RandomAccessIterator first, Distance holeIndex, Distance len, T value)
{
    Distance topIndex = holeIndex;
    Distance secondChild = 2*holeIndex+2;//right child
    while(secondChild<len)
    {
        if(*(first+secondChild) < *(first+(secondChild-1)))
            secondChild--;//bigger child
        *(first+holeIndex) = *(first+secondChild);//percolate down
        holeIndex = secondChild;
        secondChild = 2*(secondChild+1); //new right child
    }
    if(secondChild == len)//no right child only left child
    {
        *(first+holeIndex) = *(first+(secondChild-1));
        holeIndex = secondChild-1;
    }
    __push_heap(first, holeIndex, topIndex, value);//percolate up
}

 

 

priority_queue:

拥有全职观念的queue,允许从底端加入,从顶端读出。不提供迭代器

其元素并非按照加入的顺序排列,而是按照权值自动排列。底层由vector做容器,加上heap的处理规则来实现。

 

接口:

empty()

size()

top()

pop()

push()

posted @ 2012-04-22 12:57  w0w0  阅读(238)  评论(0编辑  收藏  举报