stl priority_deque
priority_deque 优先队列,STL中的优先队列实现基于完全二叉树数据格式,且对于每个父节点,他的键值都大于等于其两个子节点;由于完全二叉树的从上到下,从左向右的树节点是连续的,因此可以使用一个向量,或者队列这样的序列式容器进行数据存储,对于存储在序列式容器中的索引n节点,其父节点索引位置为(n - 1) / 2;如果其拥有子节点,那么左右节点分别为2n +1 和 2n + 2;
因此如果对于一个已经是堆的区间[begin, end);想要插入一个数据,直接将元素插入在end位置,然后不断比较对应节点与父节点关系,并进行父子关系调整即可,这样,就可以保证最终的堆的最大键值位于根节点:
void push(const value_type& __x)
{
c.push_back(__x);
std::push_heap(c.begin(), c.end(), comp);
}
template<typename _RandomAccessIterator>
inline void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
_ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
std::__push_heap(__first, _DistanceType((__last - __first) - 1), _DistanceType(0), _GLIBCXX_MOVE(__value));
}
template<typename _RandomAccessIterator, typename _Distance, typename _Tp, typename _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) = _GLIBCXX_MOVE(*(__first + __parent));
__holeIndex = __parent;
__parent = (__holeIndex - 1) / 2;
}
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}
当想要进行堆根节点的pop的时候,首先将根节点移动到数组尾部,此时根节点出现空缺,然后根据两个子节点的大小关系不断填充父节点空缺位置,不断迭代,最终到达树的叶节点层,然后将数组原本(last - 1)位置的数组填充在该位置,在进行一次push_heap即可完成堆结构;
void pop()
{
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
template<typename _RandomAccessIterator>
inline void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
if (__last - __first > 1)
{
--__last;
std::__pop_heap(__first, __last, __last);
}
}
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);
}
template<typename _RandomAccessIterator, typename _Compare>
inline void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomAccessIterator __result, _Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type
_DistanceType;
_ValueType __value = _GLIBCXX_MOVE(*__result);
*__result = _GLIBCXX_MOVE(*__first);
std::__adjust_heap(__first, _DistanceType(0),
_DistanceType(__last - __first),
_GLIBCXX_MOVE(__value), __comp);
}