手写堆一般就是完全二叉树,满足父节点小于等于子节点
数组存储堆:
1.父亲节点为 x ,则左右儿子节点分别为 2x , 2x + 1
2.插入一个数: head[++size] = x ; up(size);
3.求集合中最小值: head[1];
4.删除最小值: head[1] = head[size]; size–; down(1);
5.删除任意一个元素: head[k] = head[size]; size–;down(k);up(k);
6.修改任意一个元素: head[k] = x; down(k);up(k);可以发现dowm操作是个递归,并且down 和 up 是类似的 ,这题只要down即可
// AcWing: 堆排序
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 1e5 + 9;
int n, m, h[N], size;
// 将 根节点删除,并且寻找比根节点排名大 1 的数
void down(int u){
int t = u;
if(u * 2 <= size && h[2 * u] < h[t]) t = u * 2; //左儿子存在并且小于根节点
if(u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2; //右儿子存在并且小于根节点
if(u != t){ // 如果存在比根节点小的数,交换,并且递归下去
swap(h[u], h[t]); // 因为交换后的数字可能还是比自己的子节点小,就要继续交换
down(t);
}
}
int main(){
cin>>n>>m;
size = n;
for(int i = 1; i <= n; i++) scanf("%d",a+i);
for (int i = n / 2; i; i--) down(i); //建堆
while(m--){
printf("%d ",head[1]); //根节点是最小的数字
h[1] = h[size];
size--;
down(1); //每次输出根节点之后都要删除根节点,将第二小的数移到根节点
}
return 0;
}
其实这题sort就能过
nb