堆结构就是一种完全二叉树
每个结点的值都大于或等于其左右孩子结点的值,称之为大顶堆(左)
每个结点的值都小于或等于其左右孩子结点的值,称之为小顶堆(右)
通过数组实现堆,将数据按照层序遍历的方式存入数组
对于第i个元素满足 ki>=k2i&&ki>=k2i+1 或 ki<=k2i&&ki<=k2i+1 (i<=n/2)
结点i与它的左右孩子的关系如下图
例题 P3378 【模板】堆https://www.luogu.com.cn/problem/P3378
以小顶堆为例,在每次存取数据时,都要重新构造堆
在存数据时,将其放置到堆尾。如果比父节点小,就往上爬。
void put(int x)
{
que[++tail]=x;//放到堆尾
int now=tail;
while(now>1)
{
if(que[now]>que[now/2]) return;//若比父结点大,则返回;否则交换
int temp=que[now];
que[now]=que[now/2];
que[now/2]=temp;
now/=2;//往根结点走
}
}
在取数据时,取根结点的数据。然后将堆尾的值赋给根结点,重新构造堆
int pop()
{
int res=que[1];
que[1]=que[tail--];
int now=1;
while(now*2<=tail)
{
int next=2*now;
if(next<tail&&que[next+1]<que[next]) next++;//取较小的那堆
if(que[now]<=que[next]) return res;//如果符合小顶堆,则返回
int temp=que[now];
que[now]=que[next];
que[next]=temp;
now=next;//这里走向较小的堆
}
}
完整代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int tail=0;
int que[1000000+5];
void put(int x)
{
que[++tail]=x;//放到堆尾
int now=tail;
while(now>1)
{
if(que[now]>que[now/2]) return;//若比父结点大,则返回;否则交换
int temp=que[now];
que[now]=que[now/2];
que[now/2]=temp;
now/=2;//往根结点走
}
}
int pop()
{
int res=que[1];
que[1]=que[tail--];
int now=1;
while(now*2<=tail)
{
int next=2*now;
if(next<tail&&que[next+1]<que[next]) next++;//取较小的那堆
if(que[now]<=que[next]) return res;//如果符合小顶堆,则返回
int temp=que[now];
que[now]=que[next];
que[next]=temp;
now=next;//这里走向较小的堆
}
}
int main()
{
int n;
scanf("%d",&n);
int op;
int x;
for(int i=1;i<=n;i++)
{
scanf("%d",&op);
if(op==2) printf("%d\n",que[1]);
if(op==3) pop();
if(op==1) scanf("%d",&x),put(x);
}
return 0;
}