前面兩篇介紹了gcc4.8的vector和list的源碼實現,這是stl最經常使用了兩種序列式容器。除了容器以外,stl還提供了一種藉助容器實現特殊操做的組件,謂之適配器,好比stack,queue,priority queue等,本文就介紹gcc4.8的priority queue的源碼實現。數組
顧名思義,priority queue是帶有優先級的隊列,因此元素必須提供<操做符,與vector和list不一樣,priority queue容許加入元素,可是取出時只能取出優先級最高的元素。less
1、 priority queue定義dom
priority queue沒有基類函數
template<typename _Tp, typename _Sequence = vector<_Tp>, typename _Compare = less<typename _Sequence::value_type> > class priority_queue { public: typedef typename _Sequence::value_type value_type; typedef typename _Sequence::reference reference; typedef typename _Sequence::const_reference const_reference; typedef typename _Sequence::size_type size_type; typedef _Sequence container_type; protected: _Sequence c; _Compare comp; …...
priority queue底層默認使用vector,含有兩個成員,vector c存儲數據,comp是一個仿函數,用來比較數據大小。ui
2、 priority queue構造方式spa
能夠用vector直接初始化priority queue,也能夠任意迭代器或者數組指針初始化。指針
explicit priority_queue(const _Compare& __x, const _Sequence& __s) : c(__s), comp(__x) { std::make_heap(c.begin(), c.end(), comp); } explicit priority_queue(const _Compare& __x = _Compare(), _Sequence&& __s = _Sequence()) : c(std::move(__s)), comp(__x) { std::make_heap(c.begin(), c.end(), comp); } template<typename _InputIterator> priority_queue(_InputIterator __first, _InputIterator __last, const _Compare& __x, const _Sequence& __s) : c(__s), comp(__x) { __glibcxx_requires_valid_range(__first, __last); c.insert(c.end(), __first, __last); std::make_heap(c.begin(), c.end(), comp); } template<typename _InputIterator> priority_queue(_InputIterator __first, _InputIterator __last, const _Compare& __x = _Compare(), _Sequence&& __s = _Sequence()) : c(std::move(__s)), comp(__x) { __glibcxx_requires_valid_range(__first, __last); c.insert(c.end(), __first, __last); std::make_heap(c.begin(), c.end(), comp); }
將元素所有插入priority queue後,使用 make_heap將其建成最大堆,code
template<typename _RandomAccessIterator> void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { typedef typename iterator_traits<_RandomAccessIterator>::value_type _ValueType; typedef typename iterator_traits<_RandomAccessIterator>::difference_type _DistanceType; if (__last - __first < 2) return; const _DistanceType __len = __last - __first; _DistanceType __parent = (__len - 2) / 2; while (true) { _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent)); std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value)); if (__parent == 0) return; __parent--; } }
__adjust_heap是一個下溯過程,從最後一個非葉子節點往前一個個執行下溯過程,使得以其爲根節點的子樹是一個最大堆。blog
template<typename _RandomAccessIterator, typename _Distance, typename _Tp, typename _Compare> void __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex, _Distance __len, _Tp __value, _Compare __comp) { const _Distance __topIndex = __holeIndex; _Distance __secondChild = __holeIndex; while (__secondChild < (__len - 1) / 2) { __secondChild = 2 * (__secondChild + 1); if (__comp(*(__first + __secondChild), *(__first + (__secondChild - 1)))) __secondChild--; *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild)); __holeIndex = __secondChild; } if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2) { __secondChild = 2 * (__secondChild + 1); *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + (__secondChild - 1))); __holeIndex = __secondChild - 1; } std::__push_heap(__first, __holeIndex, __topIndex, _GLIBCXX_MOVE(__value), __comp); }
3、 priority queue的元素操做隊列
priority queue只有push和pop兩個主要操做,push增長新的元素,
void push(const value_type& __x) { c.push_back(__x); std::push_heap(c.begin(), c.end(), comp); }
先放到最後一個位置,再使用 push_heap執行一個上溯操做,將插入元素移動到合適位置,保證整個queue仍然是個最大堆。
template<typename _RandomAccessIterator, typename _Distance, typename _Tp> void __push_heap(_RandomAccessIterator __first, _Distance __holeIndex, _Distance __topIndex, _Tp __value) { _Distance __parent = (__holeIndex - 1) / 2; while (__holeIndex > __topIndex && *(__first + __parent) < __value) { *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent)); __holeIndex = __parent; __parent = (__holeIndex - 1) / 2; } *(__first + __holeIndex) = _GLIBCXX_MOVE(__value); }
pop操做移除堆頂元素,
void pop()
{
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
因爲使用的是vector,若是移除第一個元素再make_heap的話代價會很大。這裏先將第一個元素和最後一個元素交換,刪除最後一個元素,再從第一個元素作一次下溯過程,就建成了新的最大堆。