概念:
堆是一种树形结构,堆顶始终是最优值(最大或最小)。
堆一般是用二叉树实现的,称为二叉堆。
二叉堆是一种完全二叉树
堆由对顶可以分为大根堆和小根堆
————————————————————————————————
堆一般用数组去实现:
用数组A[ ]存储完全二叉树,节点数量是n,A[1]为根节点,有以下性质:
(1)i>1的节点,其父节点位于i/2
(2)如果2i>n,那么节点i没有孩子;如果2i+1>n,那么节点i没有右孩子
(3)如果节点i有孩子,那么他的左孩子是2i,右孩子是2i+1
堆有两种操作:进堆和出堆
priority_queue优先队列默认是大根堆
————————————————————————————————
模板:
struct Heap{
int data[N]={0},len=0;
void push(int e){
data[++len]=e;
int i=len;
while(i>1&&data[i]<data[i/2]){
swap(data[i],data[i/2]);
i/=2;
}
}
void pop(){
data[1]=data[len--];
int i=1;
while(2*i<=len){
int son=2*i;
if(son<len&&data[son+1]<data[son])son++;
if(data[son]<data[i]){
swap(data[son],data[i]);
i=son;
}
else break;
}
}
int top(){
return data[1];
}
};
push详解:
void push(int x) { //上浮,插入新元素
heap[++len] = x; //堆尾加入元素
int i = len;
while (i > 1 && heap[i] < heap[i / 2]) { //和它的父节点比较
swap(heap[i], heap[i / 2]);
i /= 2; //更新父节点
}
}
pop详解:
void pop() { //下沉,删除推头,调整堆
heap[1] = heap[len--]; //根节点替换为最后一个节点,节点数减一
int i = 1;
while (2 * i <= len) { //至少有一个左儿子
int son = 2 * i; //左儿子
if (son < len && heap[son + 1] < heap[son])
son++; //son<len表示有右儿子,选儿子中较小的一个
if (heap[son] < heap[i]) {
swap(heap[son], heap[i]); //与较小的儿子交换
i = son; //下沉到儿子处
}
else break; //如果不比儿子小,就停止下沉
}
}
例题:
洛谷:P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
代码:
/*---code---*/
const int N = 1e6 + 5;
struct Heap{
int data[N]={0},len=0;
void push(int e){
data[++len]=e;
int i=len;
while(i>1&&data[i]<data[i/2]){
swap(data[i],data[i/2]);
i/=2;
}
}
void pop(){
data[1]=data[len--];
int i=1;
while(2*i<=len){
int son=2*i;
if(son<len&&data[son+1]<data[son])son++;
if(data[son]<data[i]){
swap(data[son],data[i]);
i=son;
}
else break;
}
}
int top(){
return data[1];
}
};
Heap hp;
void solve(){
int q;cin>>q;
while(q--){
int op,x;
cin>>op;
if(op==1){
cin>>x;
hp.push(x);
}else if(op==2){
cout<<hp.top()<<"\n";
}else{
hp.pop();
}
}
}
STL库的priority_queue:
priority_queue本身是大根堆,我们重载一下变成小根堆
小根堆:priority_queue<int,vector<int>,greater<int>>hp;
大根堆:priority_queue<int>hp;
/*---code---*/
const int N = 1e6 + 5;
priority_queue<int,vector<int>,greater<int>>hp;
void solve(){
int q;cin>>q;
while(q--){
int op,x;
cin>>op;
if(op==1){
cin>>x;
hp.push(x);
}else if(op==2){
cout<<hp.top()<<"\n";
}else{
hp.pop();
}
}
}