stl提供了四个heap的算法:push_heap, pop_heap, make_heap, sort_heap。sgi的stl还提供了一个扩展的is_heap用来判断两个随机iterator形成的区间的是否为heap。
- // pop_heap删除__first(实际是将__first与__last-1交换),然后调用__adjust_heap调整堆。
- // [first, last)必须是合法的heap。
- template <class _RandomAccessIterator>
-
inline void pop_heap(_RandomAccessIterator __first,
-
_RandomAccessIterator __last)
-
{
- // 因为需要通过iterator改变元素的值,所以需要符合mutable random access iterator.
-
__STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
- // 要求iterator指向的元素类型是可比较的(不仅仅是可以判断小于这一种情况)。
-
__STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
-
_LessThanComparable);
- // 辅助函数
-
__pop_heap_aux(__first, __last, __VALUE_TYPE(__first));
-
}
- // 一个鸡肋的辅助函数
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, class _Tp, class _Distance>
-
inline void
-
__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
-
_RandomAccessIterator __result, _Tp __value, _Distance*)
-
{
- // result(也就是last-1)保存first指向的元素。
-
*__result = *__first;
- // 将value(原last-1位置的元素)放到合适的位置
-
__adjust_heap(__first, _Distance(0), _Distance(__last - __first), __value);
-
}
- template <class _RandomAccessIterator, class _Distance, class _Tp>
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value)
{ - // 自顶向下寻找__value合适的位置。
_Distance __topIndex = __holeIndex; - // 设置右孩子索引的位置(因为index是从0计数)
_Distance __secondChild = 2 * __holeIndex 2;
while (__secondChild < __len) { - // 如果右孩子小于左孩子,就调整__secondChild
if (*(__first __secondChild) < *(__first (__secondChild - 1)))
__secondChild--; - // 将较大的那个赋给双亲
*(__first __holeIndex) = *(__first __secondChild); - // 调整子树索引
__holeIndex = __secondChild; - // 指向新子树根节点的右孩子,这种写法真是disgusting,为什么不和上面保持一致呢?
__secondChild = 2 * (__secondChild 1);
}
- // 只有左孩子,没有右孩子
if (__secondChild == __len) { - // 直接将左子树元素赋给根节点
*(__first __holeIndex) = *(__first (__secondChild - 1));
- // 调整子树索引
- __holeIndex = __secondChild - 1;
}
- // 将__value赋给__holeIndex所属位置,并调整所在子树。
- // 在《STL源码剖析》中,侯先生认为下面的语句可以改为*(__first __holeIndex) = value
- // 但是这样一来,并不能保证value所在子树符合heap的约束。
__push_heap(__first, __holeIndex, __topIndex, __value);
}
-
template <class _RandomAccessIterator, class _Distance, class _Tp>
-
void
-
__push_heap(_RandomAccessIterator __first,
-
_Distance __holeIndex, _Distance __topIndex, _Tp __value)
-
{
- // 可以看出,依然需要根据value和*(__first __parent)的关系来决定value最终的位置。
-
_Distance __parent = (__holeIndex - 1) / 2;
-
while (__holeIndex > __topIndex && *(__first __parent) < __value) {
-
*(__first __holeIndex) = *(__first __parent);
-
__holeIndex = __parent;
-
__parent = (__holeIndex - 1) / 2;
-
}
-
*(__first __holeIndex) = __value;
-
}