STL之堆和優先隊列
阿新 • • 發佈:2018-07-01
AR tab less 劃分 compare 插入數據 child 排序 tor
STL中的heap是用數組來進行模擬的,heap 本身的定義就是一顆完全的二叉樹(註意和滿二叉樹的區別)。
heap分為大根堆和小根堆。
堆的主要操作由構建堆,調整堆,這兩個。
其中有一個heap算法就是在此基礎之上的。
構建好一顆大根堆,然後 將根頂元素和最後一個元素呼喚,將堆的大小減1,同時再次調整堆為大根堆,重復直至堆的大小為0。
由於堆結構本上是類似分組劃分的,其中修改也就是修改這條路徑上的,和其他元素沒有關系,因此,每次修改的時候也就是路徑長度,也就是二叉樹的高度。
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> inlinevoid __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); }
不過 STL提供了完整的封裝操作,可以直接用make_heap來構建堆。 sort_heap來對堆進行排序。 很是方便的。
STL中的優先隊列是利用一個大根堆,用vector來模擬完全二叉樹的結構。 優先隊列包含在queue這個頭文件下面。
STL之堆和優先隊列