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

来源:互联网 发布:神圣罗马帝国 知乎 编辑:程序博客网 时间:2024/06/08 02:03

一.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;      }  
0 0