堆是一棵完全二叉树
大根堆:父节点大于子节点
小根堆:父节点小于子节点
完全二叉树(堆)可以用一维数组存储
对父节点使用左右孩子编号法:第n个节点的左孩子是2n,右孩子是2n+1,父节点为n/2
堆可以使用stl库中的priority_queue来实现也可以手写
堆主要支持这五个操作:1、插入一个数 2、求集合中的最小值(小根堆)最大值(大根堆)3、删除最小值 4、删除任意一个元素 5、修改任意一个元素
这五个操作全部可以用up和down函数来实现
//手写堆
#include<iostream>
using namespace std;
const int N = 100010;
int h[N],Size; //Size为堆的数组长度
int n,m;
//上浮
void up(int u){
if(u / 2 && h[u] < h[u / 2]){
swap(h[u],h[u / 2]);
up(u / 2); //递归
}
}
//下沉
void down(int u){
int t = u;
if(u * 2 <= Size && h[u * 2] < h[t]) t = 2 * u;
if(u * 2 + 1 <= Size && h[u * 2 + 1] < h[t]) t = 2 * u + 1;
if(u != t) {
swap(h[u],h[t]);
down(t); //递归
}
//压入
void push(int u){
h[ ++ Size] = u;
up(Size);
}
//删除根节点
void pop(int u){
h[1] = h[Size -- ];
down(h[1]);
}
int main(){
cin >> n >> m;
//创建堆
Size = n;
for(int i = 1;i <= Size;i ++ ){
cin >> h[i];
}
for(int i = n / 2;i;i -- ) down(i);
//输出根节点即最小值,每输出一次根节点后弹出根节点,把尾节点的元素拿到根节点,重新down一遍
while(m -- ){
cout << h[1] << ' ';
h[1] = h[Size --];
down(1);
}
return 0;
}
//STL堆代码
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int>> h; //定义了一个小根堆
//弹出堆顶元素
h.pop()
//输出堆顶元素,但不会删除它
h.top()
//插入
h.push()
int main(){
int n,m;
cin >> n >> m;
while(n -- ){
int x;
cin >> x;
h.push(x);
}
while(m -- ){
cout << h.top();
h.pop();
cout << ' ';
}
return 0;
}