heap
push_heap
对于第 i 个元素,其左子节点位于 2i 处,其右子节点位于 2i+1 处。
根据元素排列方式,heap 可以分为:
- 大顶堆:每个节点键值都大于或者等于其子节点的键值。
- 小顶堆: 每个节点键值都小于或者等于其子节点的键值。
//@ 堆中添加元素;关于push_heap操作的原型有两个
//@ 注意: push_heap()操作之前必须保证新添加的元素已经加入到容器末尾
//* 第一个版本使用operator<操作
//* template< class RandomIt >
//* void push_heap( RandomIt first, RandomIt last );
//*********************************
//* 第二个版本使用比较函数comp
//* template< class RandomIt, class Compare >
//* void push_heap( RandomIt first, RandomIt last,Compare comp );
//*********************************
//* 比较函数comp:comparison function which returns true if the first argument is less than the second.
//* The signature of the comparison function should be equivalent to the following:
//* bool cmp(const Type1 &a, const Type2 &b);
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>
inline void
__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
将根节点取走后,先填入叶节点值,再将它拿来和其它两个子节点比较值,并与较大子节点对调位置,直到根节点的键值大于左右两个子节点,或者直到放至叶节点为止。
//注意: 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);
}
make_heap
//@ 创建堆
//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));
}
sort_heap
//@ 排序堆里面的内容
//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 中,heap 并不是一种容器,而是一种算法,任何能够提供随机访问迭代器的容器都能支持 heap 的操作。
- heap 不需要遍历内容,所以没有属于自己的迭代器。