1、也就是优先队列
2、本质是完全二叉树(最后一层不一定满)
3、利用数组模拟完全二叉树,下标从1开始,则2x为做孩子,2x+1为右孩子(下标从0开始,则2x + 1为左孩子, 2x + 2 为右孩子)
4、设置一个heap数组, 一个size记录,利用up和down函数来维护堆
5、up 就是不断向上找然后交换,down就是不断向下找然后交换
6、插入一个数增加放到末尾,然后利用up向上找到改呆的位置
7、小根堆的heap[1]对应最小值,大根堆的heap[1]对应最大值
8、删除heap[1],直接将最后一个数放到head[1],然后不断向下交换找到该呆的位置
9、删除任意元素需要向上或者向下交换(up,down),修改元素也是(up down),只会执行其中一个或者都不执行。
yxc视频截图
堆排序求前m个小的数
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int heap[N], sz = -1;
// 向下移动
void down(int u){ // 找到三个数中最小的
int t = u;
if(u * 2 + 1 <= sz && heap[u * 2 + 1] < heap[t]) t = u * 2 + 1;
if(u * 2 + 2 <= sz && heap[u * 2 + 2] < heap[t]) t = u * 2 + 2;
// printf("%d ", heap[u * 2 + 2]);
if(u != t){
// printf("%d ", heap[t]);
swap(heap[u], heap[t]);
down(t);
}
}
// 向上移动类似dowm
void up(int u){
// 只需对比父节点就行,只要比父节点小就一定比另一个孩子小
while(u && heap[u] < heap[(u - 1) / 2]){
swap(heap[u], heap[(u - 1) / 2];
u = (u - 1) / 2;
}
}
// 移除头
void removeHead(){
heap[0] = heap[sz --];
down(0);
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i ++) scanf("%d", &heap[++ sz]);
for(int i = n / 2; i >= 0; i --) down(i);
while(m --){
printf("%d ", heap[0]);
removeHead();
}
}