逻辑
堆是一种用数组模拟完全二叉树的结构
完全二叉树:只有最后一层是不满的,其他层都是满的,而且最后一层左满又不满
如果一个结点的位置为k,则它的父节点的位置为k/2,左子节点位置2k,右子结点2k+1
堆规定父节点大于子节点,对子节点之间的大小不做要求
代码实现
#ifndef Heap
#define Heap
using namespace std;
template <class RandomAccessIterator, class T>
//下沉操作
void _adjust_heaps(RandomAccessIterator first, int holeIndex, int len, T value){
//找到左节点和右节点中最大的
//与父节点比较如果大则交换
int maxchild = holeIndex * 2 + 2;//先假设右子结点大
//有右子结点
while(maxchild < len){
//比较两个子节点的大小
if(*(first + maxchild) < *(first + maxchild - 1)){
maxchild--;
}
//如果子节点大于父节点,将子节点的值填入洞内
if(*(first + maxchild) > value)
*(first + holeIndex) = *(first + maxchild);
//已经找到合适的位置
else{
*(first + holeIndex) = value;
return;
}
//没找到合适的位置,继续循环
holeIndex = maxchild;
maxchild = holeIndex * 2 + 2;
}
//只有左子结点(此时洞结点为最后一个父节点)
if(maxchild == len){
//如果子节点大于父节点,将子节点的值填入洞内
if(*(first + maxchild - 1) > value){
*(first + holeIndex) = *(first + maxchild - 1);
holeIndex = maxchild -1;
}
}
//根据上面if的结果,将value放到最后一个子结点或最后一个父节点
*(first + holeIndex) = value;
}
// 將 [first,last) 排列為一個 heap。
template <class RandomAccessIterator>
inline void make_heaps(RandomAccessIterator first, RandomAccessIterator last) {
if (last - first < 2) return; // 如果長度為 0 或 1,不必重新排列。
int len = last - first;
// 找出第一個需要重排的子樹頭部,以 parent 標示出。由於任何葉節點都不需執行
// perlocate down,所以有以下計算。parent 命名不佳,名為 holeIndex 更好。
int parent = (len - 2) / 2;
while (true) {
// 重排以 parent 為首的子樹。len 是為了讓 __adjust_heap() 判斷操作範圍
_adjust_heaps(first, parent, len, *(first + parent));
if (parent == 0) return; // 走完根節點,就結束。
parent--;// (即將重排之子樹的)頭部向前一個節點
}
}
template <class RandomAccessIterator, class Distance, class T>
void push_heaps(RandomAccessIterator first, RandomAccessIterator last){
//插入的元素在最后一个节点
//索引为(last - first) - 1,值为*(last - 1)
Distance holeIndex = (last - first) - 1;
//找到父节点
Distance parent = (holeIndex - 1) / 2;
T value = *(first + holeIndex);
//没到最上层且子节点大于父节点,上浮
while(parent > 0 && value > *(first + parent)){
*(first + parent) = value;
//调整洞节点到父节点
holeIndex = parent;
//调整父节点
parent = (holeIndex-1) / 2;
}
//调整完毕已经找到位置或到了顶端
*(first + holeIndex) = value;
}
template <class RandomAccessIterator>
void pop_heaps(RandomAccessIterator first, RandomAccessIterator last){
//将尾值和首值互换
RandomAccessIterator result;
*result = *first;
*first = *(last - 1);
*(last - 1) = *result;
//调整堆
_adjust_heaps(first, 0, last - first - 1, *first);
}
//堆排序
template <class RandomAccessIterator>
void sort_heaps(RandomAccessIterator first, RandomAccessIterator last){
//只需不断的对堆中元素进行pop操作,
//pop操作中将堆顶元素也就是最大元素放入最后
while(last - first > 1)
pop_heaps(first, last--);
}
#endif // Heap