堆
1 堆是一种树形数据结构
—它总是一颗完全二叉树
—堆中的某个结点总是不大于或不小于其父节点的值
—根节点的值为整个堆中的最小或最大值
2 父节点中的值大于等于(小于等于),根节点的值最大(最小)的堆称为大(小)根堆
3堆的建立
//初始化: 一个空数组,元素个数为0
const int maxn=10000;
int len=0;
int heap=[maxn+5];
4插入数据
:在堆中插入数据,,先将它放到数组末尾,再尝试逐个往上跳
//小根堆
void up(int k){
while(k>1&&heap[k]<heap[k/2]){
swap(heap[k],heap[k/2]);
k/=2;//判断当前结点的位置是否比父节点小,如果小,就交换位置
}
}
//大根堆
void up(int k){
while(k>1&&heap[k]>heap[k/2]){
swap(heap[k],heap[k/2]);
k/=2;//判断当前结点的位置是否比父节点小,如果小,就交换位置
}
}
5删除数据
:跟插入数据逆向思维,将要删除的元素与最后的元素交换,然后再去调整被交换的元素,如果是小根堆,每次取较小孩子交换值,如果是大根堆,每次取较大孩子交换–保证堆的性质
删除根节点:
//小根堆
void Pop(){
swap(heap[1],heap[len]);//删除堆顶元素
len--;
Down(1);//此时堆顶元素为原来的heap[len]
}
void Down(int k){
while(2*k<=len){
//存在左孩子
int i=2*k;
if(i+1<=len&&heap[i+1]<heap[i]) i++;
//如果右孩子存在并且右孩子的值小于小于左孩子
}
if(heap[k]<=heap[i]) break;//此时该数据已经比左右孩子都小,退出循环
swap(heap[k],heap[i]);
k=i;
}
删除任意结点:此时不仅要考虑下移,还有可能会上移
//小根堆
void delete(int p){
if(p==len){
heap[len]=0;
len--;
return;
}
int x=heap[p],y=heap[len];
swap(heap[p],heap[len]);
len--;
if(y<x){
//如果队尾的数比原来的数小,则交换后,它的孩子必定比它大,但是父亲结点不一定比它小
up(p);
}else{
//如果队尾元素比原来的数大,则交换后,它的父亲结点一定比它小,但是左右孩子不一定比它大
down(p);
}
}
6 c++ stl 库中的priority_queue(优先队列)跟手写堆类似
priority_queue<int,vector<int>,greatr<int>> pq;//构造一个小根堆
pq.empty();
pq.size();
py.top();//访问队首元素,相当于堆顶元素
py.push(); py.pop();
7 自定义排序
struct cmp1
{
bool operator()(int a, int b)
{
return a < b;
}
};
priority_queue<int, vector<int>, cmp1> pq;