STL源码剖析-序列式容器之heap和priority_queue

一.heap

1.heap概述

heap并不归属于STL容器组件,扮演priority queue的助手,binary max heap适合作为priority queue的底层机制.

binary heap是一种complete binary tree,整棵树除了最底层的叶子节点外都是填满的,而最底层的叶子节点从左至右不得有空隙.

这里写图片描述

利用array来存储complete binary tree的所有节点,将array的#0元素保留,那么当complete binary tree的某个节点位于array的i处时,其左子节点必位于array的2i处,右子节点必位于array的2i+1处.父节点必位于i/2处.

heap分为max-heap和min-heap两种,前者每个节点的键值都大于或等于其子节点的值,后者每个节点的键值都小于或等于其子节点的值.max-heap中最大值在根节点,min-heap最小值在根节点.底层存储结构为vector或者array.

2.push_heap算法

这里写图片描述

3.pop_heap算法

这里写图片描述

4.sort_heap算法

这里写图片描述

5.make_heap算法

将一段现有的数据转化为一个heap.

6.heap源码

    //在STL中,heap不作为容器,只是提供了关于Heap操作的算法。  
    //heap没有自己的迭代器,只要支持RandomAccessIterator的容器都可以作为Heap容器  
    #ifndef __SGI_STL_INTERNAL_HEAP_H  
    #define __SGI_STL_INTERNAL_HEAP_H  

    __STL_BEGIN_NAMESPACE  

    #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)  
    #pragma set woff 1209  
    #endif  

    // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap.  

    //堆中添加元素;关于push_heap操作的原型有两个  
    //注意: push_heap()操作之前必须保证新添加的元素已经加入到容器末尾  
    //***************************************************************  
    //*     第一个版本使用operator<操作  
    //*     template< class RandomIt >  
    //*     void push_heap( RandomIt first, RandomIt last );  
    //***************************************************************  
    //*     第二个版本使用比较函数comp  
    //*     template< class RandomIt, class Compare >  
    //*     void push_heap( RandomIt first, RandomIt last,Compare comp );  
    //***************************************************************  
    //* 比较函数comp:comparison function which returns true if the first argument is less than the second.   
    //* The signature of the comparison function should be equivalent to the following:  
    //*     bool cmp(const Type1 &a, const Type2 &b);  
    //***************************************************************  
    template <class _RandomAccessIterator, class _Distance, class _Tp>  
    void   
    __push_heap(_RandomAccessIterator __first,  
                _Distance __holeIndex, _Distance __topIndex, _Tp __value)  
    {//当前节点标号为__holeIndex- 1即为新插入元素标号,因为根节点标号是从0开始,所以这里要-1  
      _Distance __parent = (__holeIndex - 1) / 2;//找出当前节点的父节点  
      //尚未达到根节点,且所插入数据value大于父节点的关键字值    
      while (__holeIndex > __topIndex && *(__first + __parent) < __value) {  
        *(__first + __holeIndex) = *(__first + __parent);//交换当前节点元素与其父节点元素的值  
        __holeIndex = __parent;//更新当前节点标号,上溯  
        __parent = (__holeIndex - 1) / 2;//更新父节点  
      }   //持续达到根节点,或满足heap的性质  
      *(__first + __holeIndex) = __value;//插入正确的位置  
    }  

    template <class _RandomAccessIterator, class _Distance, class _Tp>  
    inline void   
    __push_heap_aux(_RandomAccessIterator __first,  
                    _RandomAccessIterator __last, _Distance*, _Tp*)  
    {  
        //__last - __first) - 1表示插入后元素的个数,也是容器的最后一个下标数字  
        //新插入的元素必须位于容器的末尾  
        __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),   
                  _Tp(*(__last - 1)));  
    }  

    //第一个版本push_heap默认是operator<操作  
    template <class _RandomAccessIterator>  
    inline void   
    push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,  
                     _LessThanComparable);  
      __push_heap_aux(__first, __last,  
                      __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));  
    }  

    template <class _RandomAccessIterator, class _Distance, class _Tp,   
              class _Compare>  
    void  
    __push_heap(_RandomAccessIterator __first, _Distance __holeIndex,  
                _Distance __topIndex, _Tp __value, _Compare __comp)  
    {  
      _Distance __parent = (__holeIndex - 1) / 2;  
      while (__holeIndex > __topIndex && __comp(*(__first + __parent), __value)) {  
        *(__first + __holeIndex) = *(__first + __parent);  
        __holeIndex = __parent;  
        __parent = (__holeIndex - 1) / 2;  
      }  
      *(__first + __holeIndex) = __value;  
    }  

    template <class _RandomAccessIterator, class _Compare,  
              class _Distance, class _Tp>  
    inline void   
    __push_heap_aux(_RandomAccessIterator __first,  
                    _RandomAccessIterator __last, _Compare __comp,  
                    _Distance*, _Tp*)   
    {  
      __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),   
                  _Tp(*(__last - 1)), __comp);  
    }  
    //第二个版本push_heap自定义比较操作函数comp  
    template <class _RandomAccessIterator, class _Compare>  
    inline void   
    push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,  
              _Compare __comp)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __push_heap_aux(__first, __last, __comp,  
                      __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));  
    }  

    //注意: pop_heap()操作, 执行完操作后要自己将容器尾元素弹出  
    //default (1):    
    //          template <class RandomAccessIterator>  
    //          void pop_heap (RandomAccessIterator first, RandomAccessIterator last);  
    //custom (2):     
    //          template <class RandomAccessIterator, class Compare>  
    //          void pop_heap (RandomAccessIterator first, RandomAccessIterator last,  
    //                 Compare comp);  
    //***********************************************************************  
    template <class _RandomAccessIterator, class _Distance, class _Tp>  
    void   
    __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,  
                  _Distance __len, _Tp __value)  
    {  
      _Distance __topIndex = __holeIndex;//根节点标号  
      _Distance __secondChild = 2 * __holeIndex + 2;//获取子节点  
      while (__secondChild < __len) {//若子节点标号比总的标号数小  
        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);  
    }  

    template <class _RandomAccessIterator, class _Tp, class _Distance>  
    inline void   
    __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,  
               _RandomAccessIterator __result, _Tp __value, _Distance*)  
    {  
      *__result = *__first;//把原始堆的根节点元素放在容器的末尾  
      //调整剩下的节点元素,使其成为新的heap  
      __adjust_heap(__first, _Distance(0), _Distance(__last - __first), __value);  
    }  

    template <class _RandomAccessIterator, class _Tp>  
    inline void   
    __pop_heap_aux(_RandomAccessIterator __first, _RandomAccessIterator __last,  
                   _Tp*)  
    {  
      __pop_heap(__first, __last - 1, __last - 1,   
                 _Tp(*(__last - 1)), __DISTANCE_TYPE(__first));  
    }  

    template <class _RandomAccessIterator>  
    inline void pop_heap(_RandomAccessIterator __first,   
                         _RandomAccessIterator __last)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,  
                     _LessThanComparable);  
      __pop_heap_aux(__first, __last, __VALUE_TYPE(__first));  
    }  

    template <class _RandomAccessIterator, class _Distance,  
              class _Tp, class _Compare>  
    void  
    __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,  
                  _Distance __len, _Tp __value, _Compare __comp)  
    {  
      _Distance __topIndex = __holeIndex;  
      _Distance __secondChild = 2 * __holeIndex + 2;  
      while (__secondChild < __len) {  
        if (__comp(*(__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, __comp);  
    }  

    template <class _RandomAccessIterator, class _Tp, class _Compare,   
              class _Distance>  
    inline void   
    __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,  
               _RandomAccessIterator __result, _Tp __value, _Compare __comp,  
               _Distance*)  
    {  
      *__result = *__first;  
      __adjust_heap(__first, _Distance(0), _Distance(__last - __first),   
                    __value, __comp);  
    }  

    template <class _RandomAccessIterator, class _Tp, class _Compare>  
    inline void   
    __pop_heap_aux(_RandomAccessIterator __first,  
                   _RandomAccessIterator __last, _Tp*, _Compare __comp)  
    {  
      __pop_heap(__first, __last - 1, __last - 1, _Tp(*(__last - 1)), __comp,  
                 __DISTANCE_TYPE(__first));  
    }  

    template <class _RandomAccessIterator, class _Compare>  
    inline void   
    pop_heap(_RandomAccessIterator __first,  
             _RandomAccessIterator __last, _Compare __comp)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __pop_heap_aux(__first, __last, __VALUE_TYPE(__first), __comp);  
    }  


    //创建堆  
    //default(1):     
    //          template <class RandomAccessIterator>  
    //          void make_heap (RandomAccessIterator first, RandomAccessIterator last);  
    //custom (2):     
    //          template <class RandomAccessIterator, class Compare>  
    //          void make_heap (RandomAccessIterator first, RandomAccessIterator last,Compare comp );  
      //********************************************************************************  
    template <class _RandomAccessIterator, class _Tp, class _Distance>  
    void   
    __make_heap(_RandomAccessIterator __first,  
                _RandomAccessIterator __last, _Tp*, _Distance*)  
    {  
      if (__last - __first < 2) return;  
      _Distance __len = __last - __first;  
      _Distance __parent = (__len - 2)/2;  

      while (true) {  
        __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)));  
        if (__parent == 0) return;  
        __parent--;  
      }  
    }  

    template <class _RandomAccessIterator>  
    inline void   
    make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,  
                     _LessThanComparable);  
      __make_heap(__first, __last,  
                  __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));  
    }  

    template <class _RandomAccessIterator, class _Compare,  
              class _Tp, class _Distance>  
    void  
    __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,  
                _Compare __comp, _Tp*, _Distance*)  
    {  
      if (__last - __first < 2) return;  
      _Distance __len = __last - __first;  
      _Distance __parent = (__len - 2)/2;  

      while (true) {  
        __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)),  
                      __comp);  
        if (__parent == 0) return;  
        __parent--;  
      }  
    }  

    template <class _RandomAccessIterator, class _Compare>  
    inline void   
    make_heap(_RandomAccessIterator __first,   
              _RandomAccessIterator __last, _Compare __comp)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __make_heap(__first, __last, __comp,  
                  __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));  
    }  

    //排序堆里面的内容  
    //default(1):     
    //          template <class RandomAccessIterator>  
    //          void sort_heap (RandomAccessIterator first, RandomAccessIterator last);  
    //custom (2):     
    //          template <class RandomAccessIterator, class Compare>  
    //          void sort_heap (RandomAccessIterator first, RandomAccessIterator last,  
    //                        Compare comp);  
    //**************************************************************************  
    template <class _RandomAccessIterator>  
    void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,  
                     _LessThanComparable);  
      while (__last - __first > 1)  
        pop_heap(__first, __last--);//每次取出根节点元素,直到heap为空  
    }  

    template <class _RandomAccessIterator, class _Compare>  
    void   
    sort_heap(_RandomAccessIterator __first,  
              _RandomAccessIterator __last, _Compare __comp)  
    {  
      __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);  
      while (__last - __first > 1)  
        pop_heap(__first, __last--, __comp);  
    }  

    #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)  
    #pragma reset woff 1209  
    #endif  

    __STL_END_NAMESPACE  

    #endif /* __SGI_STL_INTERNAL_HEAP_H */  

    // Local Variables:  
    // mode:C++  
    // End:  

7.heap测试实例

    #include<vector>  
    #include<iostream>  
    #include<algorithm> //heap algorithm  
    using namespace std;  

    int main(void){  
        {   //test heap(底层以vector完成)  
            int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };  
            vector<int> ivec(ia, ia + 9);  

            make_heap(ivec.begin(), ivec.end());  
            for (int i = 0; i < ivec.size(); ++i)  
                cout << ivec[i] << ' ';  
            cout << endl;  

            ivec.push_back(7);  
            push_heap(ivec.begin(), ivec.end());  
            for (int i = 0; i < ivec.size(); ++i)  
                cout << ivec[i] << ' ';  
            cout << endl;  

            pop_heap(ivec.begin(), ivec.end());  
            cout << ivec.back() << endl;  
            ivec.pop_back();  

            for (int i = 0; i < ivec.size(); ++i)  
                cout << ivec[i] << ' ';  
            cout << endl;  

            sort_heap(ivec.begin(), ivec.end());  
            for (int i = 0; i < ivec.size(); ++i)  
                cout << ivec[i] << ' ';  
            cout << endl;  
        }  
        {   //test heap (底层以array 完成)  
            int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };  
            make_heap(ia, ia + 9);  


            sort_heap(ia, ia + 9);  
            for (int i = 0; i < 9; ++i)  
            {  
                cout << ia[i] << ' ';  
            }  
            cout << endl;  
        }  
        {   //test heap (底层以array完成)  
            int ia[6] = { 4, 1, 7, 6, 2, 5 };  
            make_heap(ia, ia + 6);  
            for (int i = 0; i < 6; ++i)  
                cout << ia[i] << ' ';  
            cout << endl;  
        }  
        system("pause");  
        return 0;  
    }  

二.priority_queue

1.priority_queue概述

priority_queue是一个拥有权值观念的queue,它允许加入新元素,移除旧元素,审视元素值等功能.只允许在低端加入元素,并从顶端取出元素,除此之外别无其他存取元素的途径.

priority_queue缺省情况下是以vector为底层容器,再加上heap处理规则,STL priority_queue往往不被归类为Container(容器),而被归类为container adapter.

2.测试实例

    #include<queue>  
    #include<iostream>  
    #include<algorithm>  
    using namespace std;  

    int main(void){  
        //test priority queue...  
        int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };  
        priority_queue<int> ipq(ia, ia + 9);  
        cout << "size= " << ipq.size() << endl;  

        for (int i = 0; i < ipq.size(); ++i)  
            cout << ipq.top() << ' ';  
        cout << endl;  

        while (!ipq.empty()){  
            cout << ipq.top() << ' ';  
            ipq.pop();  
        }  
        cout << endl;  

        system("pause");  
        return 0;  
    }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值