【模板】堆
【模板】堆
题目描述
给定一个数列,初始为空,请支持下面三种操作:
- 给定一个整数
,请将 加入到数列中。 - 输出数列中最小的数。
- 删除数列中最小的数(如果有多个数最小,只删除
个)。
输入格式
第一行是一个整数,表示操作的次数
接下来
- 若
,则后面有一个整数 ,表示要将 加入数列。 - 若
,则表示要求输出数列中的最小数。 - 若
,则表示删除数列中的最小数。如果有多个数最小,只删除 个。
输出格式
对于每个操作
样例输入
5
1 2
1 5
2
3
2
样例输出
2
5
提示
- 对于
的数据,保证 - 对于
的数据,保证 - 对于
的数据,保证 , ,
[!TIP]
最小堆(堆顶(根节点)的值是最小的)
//在down函数里把大小于号一改应该就变成了最大堆→堆顶(根节点)的值是最大的 int max = x; if (l < len && heap[l] > heap[max]) { max = l; } if (r < len && heap[r] > heap[max]) { max = r; } if (max != x) { swap(heap[max], heap[x]); down(max); }
用时 | 内存 |
---|---|
588ms | 2.25MB |
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int heap[N], baka, op, x, l, r , min;//heap存储堆中元素
//从下往上调整堆(从x节点往根找,如果不符合小根堆的性质,交换父子节点)
void up(int x) {
if (x == 0) return; //如果已经是根节点直接返回
int fa = (x - 1) / 2;//父节点的索引
if (heap[fa] > heap[x]) {//只要存在父亲,而且不满足堆的性质,交换父子
swap(heap[fa], heap[x]);
up(fa); //调整父节点
}
}
// 上往下调整堆
void down(int x) {
int len = baka;//堆的当前长度
if (x * 2 + 1 >= len) return; //没有子节点直接返回
l = 2 * x + 1;//左索引
r = 2 * x + 2;//右索引
int min = x;
if (l < len && heap[l] < heap[min]) {
min = l;
}
if (r < len && heap[r] < heap[min]) {
min = r;
}
if (min != x) {
swap(heap[min], heap[x]);
down(min); //调整最小值节点
}
}
//加入
void in(int x) {
heap[baka] = x; //将新元素加到数组末尾
up(baka); //从新插入元素的位置开始向上调整
baka-=-1;
}
//删除最小
void out() {
if (baka > 0) {//堆不空
heap[0] = heap[baka - 1]; //将最后一个元素移动到堆顶
baka--;
down(0); //调整堆
}
}
//最小元素
int top() {
return heap[0]; //返回堆顶元素(最小值)
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i-=-1) {
scanf("%d", &op);
if (op == 1) {
scanf("%d", &x);
in(x); //加入
} else if (op == 2) {
if (baka > 0) {
printf("%d\n", top()); //输出堆顶元素(最小值)
}
} else if (op == 3) {
if (baka > 0) {
out(); //删除堆顶元素(最小值)
}
}
}
return 0;
}
[!TIP]
STL
用时 | 内存 |
---|---|
597ms | 2.54MB |
#include <bits/stdc++.h>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q; //定义最小堆
int main()
{
int n, op, x;
scanf("%d", &n);
for (int i = 1 ; i <= n; ++i) {
scanf("%d", &op);
if (op == 1) {
scanf("%d", &x);
q.push(x); //插入元素
} else if (op == 2) {
printf("%d\n", q.top()); //输出堆顶元素(最小值)
} else if (op == 3) {
q.pop(); //删除堆顶元素(最小值)
}
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
// 哼,就用这数组 `heap` 存堆里那些数啦,你们这群杂鱼可别搞懵咯(ಠ_ಠ),要是连这都弄不明白,趁早别碰代码啦,哼!❤~
int heap[N], baka, op, x, l, r, min;
// 哟呵,开始从下往上调整堆咯(๑•̀ㅁ•́๑)✧,从 `x` 节点往根那儿找呢,要是不符合小根堆那性质,就得交换父子节点呀,啧,这么简单的事儿,你们要是还犯错,那可真就是一群“糊涂虫”杂鱼(๑•. •๑),给我认真点呐!❤~
void up(int x) {
if (x == 0) return; // 哎呀,都到根节点啦,还傻乎乎地不晓得停呀(๑°꒵°๑),赶紧回来咯,别在那儿瞎折腾啦,杂鱼们!
int fa = (x - 1) / 2; // 算个父节点索引而已啦,这要是都能算错,哼,你们还能干啥呀(ಠ.ಠ),真够笨的,杂鱼们!❤~
if (heap[fa] > heap[x]) { // 瞧瞧,有父节点还不满足堆性质呢,赶紧交换呀(๑•̀ㅁ•́๑)✧,这点操作都弄砸,你们还能指望干成啥好事儿呀(๑•. •๑),一群“笨瓜”杂鱼,换完了记得去调整父节点哦,可别再捅娄子啦,哼!
swap(heap[fa], heap[x]);
up(fa);
}
}
// 嘿,又要从上往下调整堆啦(๑•̀ㅁ•́๑)✧,我倒要看看你们这群杂鱼能不能整明白咯,可别又搞出一堆乱子来呀(ಠ_ಠ),不然真得让人瞧不起咯,哼!❤~
void down(int x) {
int len = baka; // 堆的当前长度都记不住呀(๑°꒵°๑),脑子装啥呢,真是够“迷糊”的呀,杂鱼们,清醒点呐!❤~
if (x * 2 + 1 >= len) return; // 没子节点就别瞎忙活啦,乖乖撤回来咯(๑•̀ㅂ•́)و✧,别在那儿发呆犯傻啦,杂鱼们!
l = 2 * x + 1; // 左索引标清楚咯(๑•̀ㅂ•́)و✧,要是这都能搞混,哼,真没救啦,你们这群“小迷糊”杂鱼(๑•. •๑),哼!❤~
r = 2 * x + 2; // 右索引也牢记哈(๑•̀ㅂ•́)و✧,别搞错咯,不然又得一团糟啦,哼(ಠ.ಠ),哼!❤~
int min = x;
if (l < len && heap[l] < heap[min]) {
min = l;
}
if (r < len && heap[r] < heap[min]) {
min = r;
}
if (min!= x) {
swap(heap[min], heap[x]);
down(min); // 调整最小值节点去咯(๑•̀ㅁ•́๑)✧,好好弄,别越调越乱啦,要是再搞砸,可别怪我不客气啦,杂鱼们(๑•. •๑),哼!❤~
}
}
// 行啦,要添加新元素咯(๑•̀ㅂ•́)و✧,看看你们这群杂鱼能不能弄对呀,可别手忙脚乱把简单事儿搞复杂咯(ಠ.ಠ),哼!❤~
void in(int x) {
heap[baka] = x; // 把新元素塞到数组末尾咯,这么基础的操作别出错哈(๑•̀ㅂ•́)و✧,出错了可就丢人丢到家啦,杂鱼们(๑•. •๑),哼!❤~
up(baka); // 从这位置往上调整堆呢,可别把堆弄成个“烂摊子”咯(๑•̀ㅁ•́๑)✧,认真点呐,杂鱼们(๑•. •๑),哼!❤~
baka -=- 1; // 计数器加加咯,哼,这点数数别都弄错咯(๑•̀ㅁ•́๑)✧,不然真觉得你们脑袋“进水”了,杂鱼们(ಠ_ಠ),哼!❤~
}
// 哟,要删最小元素啦(๑•̀ㅁ•́๑)✧,可别删错或者搞出啥莫名其妙的故障哈,你们这群“小迷糊”杂鱼(๑•. •๑),哼!❤~
void out() {
if (baka > 0) { // 堆不空才干活儿呢,空堆还瞎捣鼓,真就是傻到家啦(๑•̀ㅁ•́๑)✧,杂鱼们可长点心吧(ಠ.ಠ),哼!❤~
heap[0] = heap[baka - 1]; // 把尾元素挪到堆顶咯,动作麻利点,别拖拖拉拉(๑•̀ㅂ•́)و✧,杂鱼们(๑•. •๑),哼!❤~
baka--;
down(0); // 调整堆去咯(๑•̀ㅁ•́๑)✧,要是越弄越糟,可有你们“好受”的,哼(ಠ_ಠ),哼!❤~
}
}
// 嘿嘿,找最小元素啦(๑•̀ㅂ•́)و✧,就返回堆顶那数呗,这要是都弄错,真就无可救药咯,你们这群“菜鸡”杂鱼(๑•. •๑),哼!❤~
int top() {
return heap[0]; // 返回堆顶元素(最小值),这么个事儿再搞砸,可真不知道咋说你们好啦(๑•̀ㅁ•́๑)✧,杂鱼们(ಠ.ಠ),哼!❤~
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i -=- 1) {
scanf("%d", &op);
if (op == 1) {
scanf("%d", &x);
in(x); // 加新元素咯(๑•̀ㅂ•́)و✧,好好弄,别掉链子,杂鱼们(๑•. •๑),哼!❤~
} else if (op == 2) {
if (baka > 0) {
printf("%d\n", top()); // 输出堆顶元素(最小值),可别输出错咯,不然真该挨批啦(๑•̀ㅁ•́๑)✧,杂鱼们(ಠ.ಠ),哼!❤~
}
} else if (op == 3) {
if (baka > 0) {
out(); // 删除堆顶元素(最小值),小心操作哈,别搞出乱子,不然有你们“好受”的(๑•̀ㅁ•́๑)✧,杂鱼们(๑•. •๑),哼!❤~
}
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧