#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
template<class T> //利用仿函数,可以完成代码的复用,这里我们假设建立大堆。
struct Greater
{
bool operator()(const T& x1, const T& x2)
{
return x1 > x2;
}
};
template<class T>
struct Less
{
bool operator()(const T& x1, const T& x2)
{
return x1 < x2;
}
};
template<class T,class Compare> //堆基本结构
class Heap
{
public:
Heap()
{}
Heap(T* a, size_t n)
{
_a.reserve(n);
for (size_t i = 0; i < n; ++i)
{
_a.push_back(a[i]);
}
//建堆
//O(N*lgN)
for (int i = (_a.size() - 2) / 2; i >= 0; --i) //这里i的初始值是先找到最后一个孩子的下标,再通过计算得出第一个父亲的下标
{
_AdjustDown(i); //向下调整算法
}
}
void Push(const T& x)//插入一个数
{
_a.push_back(x);
_AdjustUp(_a.size() - 1);//向上调整算法
}
void Pop()//删除
{
assert(!_a.empty());
swap(_a[0], _a[_a.size() - 1]);//把要删除的_a[0}与最后一个下标交换
_a.pop_back(); //删除交换后的最后的数
_AdjustDown(0); // 从0这个位置向下调整
}
const T& Top() //取堆顶的数--》_a[0]
{
return _a[0];
}
size_t Size()
{
return _a.size();
}
bool Empty()
{
return _a.empty();
}
protected:
void _AdjustDown(size_t root)//向下调整
{
Compare com;
size_t parent = root; //把root传给父亲
size_t child = parent * 2 + 1;//通过父亲节点找到左孩子节点
while (child < _a.size())
{
if (child + 1 < _a.size() && com(_a[child + 1] , _a[child])) //用了一个仿函数按需要比较左孩子和右孩子的数找出大的孩子的下标。
{
++child;
}
if(com(_a[child] ,_a[parent])) //比较孩子和父亲的值,如果孩子比父亲大
{
swap(_a[child], _a[parent]);//交换父亲和孩子的值
parent = child; // 将孩子的下标赋值给父亲
child = parent * 2 + 1;// 更新孩子的下标,继续向下调整
}
else
{
break;
}
}
}
void _AdjustUp(size_t i)//向上调整算法
{
Compare com;
int child = i; //确定最后一个孩子的下标
int parent = (child - 1) >> 2; //找到父亲的下标
while (parent >= 0) //循环条件 一直往上调,直到父亲的下<0停止循环
{
if (child + 1 < _a.size() && com(_a[child + 1] ,_a[child]))//比较左右孩子,找到大的孩子下标
{
++child;
}
if(com(_a[child],_a[parent])) //如果孩子值比父亲大
{
swap(_a[child], _a[parent]); //交换父子值
child = parent; //向上调整 ,将父亲下标给孩子
parent = (child - 1) >> 2; // 更新父亲的下标
}
else
{
break;
}
}
}
vector<T> _a;
};
父亲下标=(孩子下标-1)/2 parent=(child-1)>>2
左孩子下标=(父亲下标)*2+1 child=parent*2+1