heap
默认追加元素push_heap()
在范围[first, last)的最后一个位置存放着新添加的元素,调整该元素的位置,使[first, last)满足堆的要求。
默认大顶堆。
template <class RandomAccessIterator>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) {//注意新元素已经被放置在最尾部
__push_heap_aux(first, last, distance_type(first), value_type(first));
}
template <class RandomAccessIterator, class Distance, class T>
inline void __push_heap_aux(RandomAccessIterator first,
RandomAccessIterator last, Distance*, T*) {
__push_heap(first, Distance((last - first) - 1)/*新插入节点下标*/, Distance(0),
T(*(last - 1))/*新插入节点值*/);
}
以first+holeIndex作为需要调整的初始位置,value作为需要调整的值,不断向上调整,直到满足堆要求。
//以first作为容器开始,以first+topIndex作为堆开始,以first+holeIndex作为需要调整的位置。value为需要调整的值
template <class RandomAccessIterator, class Distance, class T>
void __push_heap(RandomAccessIterator first, Distance holeIndex/*堆顶下标,相对与first为0*/,
Distance topIndex/*插入位置下标,也是相对于first的下标*/, T value/*插入元素的值*/) {
Distance parent = (holeIndex - 1) / 2;//获取插入节点父节点下标(i-1)/2
while (holeIndex > topIndex && *(first + parent) < value) {//判断是否上溯:当前节点下标大于顶点下标并且父节点
//值小于插入节点的值。
*(first + holeIndex) = *(first + parent);//将父节点数据复制到子节点当中
holeIndex = parent;//修改需要调整的下标位置
parent = (holeIndex - 1) / 2;//获取父节点
}
*(first + holeIndex) = value;//最后将该值插入合适位置
}
可选择方式追加元素push_heap()
template <class RandomAccessIterator, class Compare>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last,
Compare comp/*可以指定比较方式*/) {
__push_heap_aux(first, last, comp, distance_type(first), value_type(first));
}
template <class RandomAccessIterator, class Compare, class Distance, class T>
inline void __push_heap_aux(RandomAccessIterator first,
RandomAccessIterator last, Compare comp,
Distance*, T*) {
__push_heap(first, Distance((last - first) - 1), Distance(0),
T(*(last - 1)), comp);
}
template <class RandomAccessIterator, class Distance, class T, class Compare>
void __push_heap(RandomAccessIterator first, Distance holeIndex,
Distance topIndex, T value, Compare comp) {
Distance parent = (holeIndex - 1) / 2;
while (holeIndex > topIndex && comp(*(first + parent), value)) {//如果comp实现为:
//1)a<b true则为大顶堆
//2)a>b true则为小顶堆
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1) / 2;
}
*(first + holeIndex) = value;
}
默认取出堆顶元素pop_heap()
当前堆范围为[first, last),提取堆顶元素放在last-1位置,然后对[first, last-1)进行调整。
由于提取了极值,所以堆顶为空,因此不断从左右子树中提取较大值放入父节点中,最后结果为某个叶子节点为空,因此被极值占用的节点中的元素数据应该放在此处,但是当插入此节点之后,还需要调整。
template <class RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) {
__pop_heap_aux(first, last, value_type(first));
}
template <class RandomAccessIterator, class T>
inline void __pop_heap_aux(RandomAccessIterator first,
RandomAccessIterator last, T*) {
__pop_heap(first, last - 1, last - 1, T(*(last - 1)), distance_type(first));//提取的值被放在last-1位置,
//重新调整first,last-1
}
template <class RandomAccessIterator, class T, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,//新范围
RandomAccessIterator result, T value/*需要调整的值*/, Distance*) {//结果位置,末尾值(待调整值)
*result = *first;//将极值放在末尾
__adjust_heap(first, Distance(0), Distance(last - first), value);
}
//取出极值之后的调整+插入末尾值之后的调整
template <class RandomAccessIterator, class Distance, class T>
void __adjust_heap(RandomAccessIterator first/*堆顶位置*/, Distance holeIndex,/*待调整位置*/
Distance len/*堆中元素个数*/, T 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 Compare>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last,
Compare comp) {
__pop_heap_aux(first, last, value_type(first), comp);
}
template <class RandomAccessIterator, class T, class Compare>
inline void __pop_heap_aux(RandomAccessIterator first,
RandomAccessIterator last, T*, Compare comp) {
__pop_heap(first, last - 1, last - 1, T(*(last - 1)), comp,
distance_type(first));
}
template <class RandomAccessIterator, class T, class Compare, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,
RandomAccessIterator result, T value, Compare comp,
Distance*) {
*result = *first;
__adjust_heap(first, Distance(0), Distance(last - first), value, comp);
}
template <class RandomAccessIterator, class Distance, class T, class Compare>
void __adjust_heap(RandomAccessIterator first, Distance holeIndex,
Distance len, T value, Compare comp) {
Distance topIndex = holeIndex;
Distance secondChild = 2 * holeIndex + 2;
while (secondChild < len) {
if (comp(*(first + secondChild), *(first + (secondChild - 1))))//如果a<b则为大顶堆
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);
}
构造默认堆make_heap()
从最后一个非叶子节点开始到堆顶元素为止,先保存当前节点的值,然后将该节点作为空,不断从子节点中抽取最大值填充,直到叶子节点,然后调整向上调整该节点的位置。
template <class RandomAccessIterator>
inline void make_heap(RandomAccessIterator first, RandomAccessIterator last) {//可以看到必须为随机迭代器
__make_heap(first, last, value_type(first), distance_type(first));//之后的两个参数为传递元素类型和距离类型
//之所以为指针是为了避免分配内存,因为不需要变量,只需要传递类型
}
template <class RandomAccessIterator, class T, class Distance>
void __make_heap(RandomAccessIterator first, RandomAccessIterator last, T*,
Distance*) {
if (last - first < 2) return;//如果小于2个元素,则不需构建堆
Distance len = last - first;
Distance parent = (len - 2)/2;//计算最后一个非叶子节点
while (true) {
__adjust_heap(first, parent, len, T(*(first + parent)));//以parent为空的调整+插入原始parent中值的调整
if (parent == 0) return;//直到调整过堆顶之后退出
parent--;
}
}
可选择构造堆make_heap()
template <class RandomAccessIterator, class Compare>
inline void make_heap(RandomAccessIterator first, RandomAccessIterator last,
Compare comp) {
__make_heap(first, last, comp, value_type(first), distance_type(first));
}
template <class RandomAccessIterator, class Compare, class T, class Distance>
void __make_heap(RandomAccessIterator first, RandomAccessIterator last,
Compare comp, T*, Distance*) {
if (last - first < 2) return;
Distance len = last - first;
Distance parent = (len - 2)/2;
while (true) {
__adjust_heap(first, parent, len, T(*(first + parent)), comp);
if (parent == 0) return;
parent--;
}
}
堆排序
template <class RandomAccessIterator>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last) {
while (last - first > 1) pop_heap(first, last--); //不断从极值提取元素放在last-1位置
}
template <class RandomAccessIterator, class Compare>
void sort_heap(RandomAccessIterator first, RandomAccessIterator last,
Compare comp) {
while (last - first > 1) pop_heap(first, last--, comp);
}