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);
}

 

posted @ 2021-06-14 23:10  呵哈呵  阅读(19)  评论(0)    收藏  举报