STL源码剖析-序列式容器之heap和priority_queue
2017-04-20 11:36
513 查看
一.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源码
7.heap测试实例
二.priority_queue
1.priority_queue概述
priority_queue是一个拥有权值观念的queue,它允许加入新元素,移除旧元素,审视元素值等功能.只允许在低端加入元素,并从顶端取出元素,除此之外别无其他存取元素的途径.
priority_queue缺省情况下是以vector为底层容器,再加上heap处理规则,STL priority_queue往往不被归类为Container(容器),而被归类为container adapter.
2.测试实例
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 (__c deda omp(*(__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; }
相关文章推荐
- Chapter 4: 序列式容器之 heap and priority queue
- STL源码剖析 - 第4章 序列式容器 - priority_queue
- 【STL源码剖析读书笔记】【第4章】序列式容器之heap和priority_queue
- 三 序列式容器(五)priority_queue(heap)(container adapter)
- 【STL源码剖析读书笔记】【第4章】序列式容器之heap和priority_queue
- STL 源码剖析读书笔记五:序列式容器之 heap、priority_queue、slist
- STL源码剖析——容器配接器之priority_queue
- STL源码剖析 - 第4章 序列式容器 - heap
- STL源码剖析-序列式容器之stack和queue
- 【优先队列】【堆】STL之priority_queue、make_heap()、push_heap()、pop_heap()、容器适配器
- STL源码剖析 - 第4章 序列式容器 - queue
- STL序列式容器之优先队列——priority_queue
- STL源码剖析 [容器](八)[priority_queue]
- C++中堆的应用:make_heap, pop_heap, push_heap, sort_heap, priority_queue
- Heap && Priority_Queue
- 从一道整数合并问题学习 STL 之make_heap &&priority_queue&&multiset
- 【STL】序列式容器--stack和queue
- C++ STL queue,priority_queue,stack,容器适配器
- STL源码剖析 - 第4章 序列式容器 - list
- 《STL源码剖析》-序列式容器(二)list容器