【模板】堆

【模板】堆

题目描述

给定一个数列,初始为空,请支持下面三种操作:

  1. 给定一个整数 x,请将 x 加入到数列中。
  2. 输出数列中最小的数。
  3. 删除数列中最小的数(如果有多个数最小,只删除 1 个)。

输入格式

第一行是一个整数,表示操作的次数 n
接下来 n 行,每行表示一次操作。每行首先有一个整数 op 表示操作类型。

  • op=1,则后面有一个整数 x,表示要将 x 加入数列。
  • op=2,则表示要求输出数列中的最小数。
  • op=3,则表示删除数列中的最小数。如果有多个数最小,只删除 1 个。

输出格式

对于每个操作 2,输出一行一个整数表示答案。

样例输入

5
1 2
1 5
2
3
2

样例输出

2
5

提示

  • 对于 30% 的数据,保证 n15
  • 对于 70% 的数据,保证 n104
  • 对于 100% 的数据,保证 1n1061x<231op{1,2,3}

[!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;
}
posted @   土木牢盖  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示