堆,又叫优先队列。堆是一颗完全二叉树结构(除了最后一层节点之外,上面所有节点都是为满的,最后一层,从左到右排列)。
手写堆的基本要求:
- 插入一个数
- 求集合中的最小值
- 删除最小值
- 删除任意一个元素
- 修改任意一个元素
小根堆:
大根堆:
堆的两个基本操作:
down:
把一个节点往下移动,使满足根堆的性质
up
把一个节点往上移动,使满足根堆的性质
- 如果根节点比当前节点大,就交换
- 交换到不能交换或者到顶根节点
堆节点的组合操作
插入操作:
删除最小值操作:
- heap[1] = heap[size], size–; down(1);
删除任意一个元素:
- heap[k] = heap[size]; size–; up[k];
修改任意一个元素:
- heap[k] = x; down(k); up(k);
注意: 下标从1开始比较方便。
题目:堆排序
来源: https://www.acwing.com/problem/content/840/
输入一个长度为n的整数数列,从小到大输出前m小的数。
输入格式
第一行包含整数n和m。
第二行包含n个整数,表示整数数列。
输出格式
共一行,包含m个整数,表示整数数列中前m小的数。
数据范围
$1≤m≤n≤10^5,$
$1≤数列中元素≤10^9$
输入样例:
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream>
using namespace std; const int N = 100010;
int n, m; int h[N], cnt;
void down(int x) { int t = x; if (2 * x <= cnt && h[2 * x] < h[t]) t = 2 * x; if (2 * x + 1 <= cnt && h[2 * x + 1] < h[t]) t = 2 * x + 1; if (t != x) { swap(h[t], h[x]); down(t); } }
int main() { cin >> n >> m; for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
cnt = n; for(int i = cnt / 2; i; i--) down(i);
for(int i = 0; i < m; i++) { printf("%d ", h[1]); h[1] = h[cnt--]; down(1); } return 0; }
|
题目: 模拟堆
来源: https://www.acwing.com/problem/content/841/
维护一个集合,初始时集合为空,支持如下几种操作:
“I x”,插入一个数x;
“PM”,输出当前集合中的最小值;
“DM”,删除当前集合中的最小值(数据保证此时的最小值唯一);
“D k”,删除第k个插入的数;
“C k x”,修改第k个插入的数,将其变为x;
现在要进行N次操作,对于所有第2个操作,输出当前集合的最小值。
输入格式
第一行包含整数N。
接下来N行,每行包含一个操作指令,操作指令为”I x”,”PM”,”DM”,”D k”或”C k x”中的一种。
输出格式
对于每个输出指令“PM”,输出一个结果,表示当前集合中的最小值。
每个结果占一行。
数据范围
$1≤N≤10^5$
$−10^9≤x≤10^9$
数据保证合法。
输入样例:
1 2 3 4 5 6 7 8 9
| 8 I -10 PM I -10 D 1 C 2 8 I 6 PM DM
|
输出样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #include <iostream> #include <algorithm> #include <string.h> using namespace std;
const int N = 100010;
int h[N], ph[N], hp[N], cnt;
void heap_swap(int x, int y) { swap(ph[hp[x]], ph[hp[y]]); swap(hp[x], hp[y]); swap(h[x], h[y]); }
void down(int x) { int t = x; if ( 2 * x <= cnt && h[2 * x] < h[t]) t = 2 * x; if ( 2 * x + 1 <= cnt && h[2 * x + 1] < h[t]) t = 2 * x + 1; if (t != x) { heap_swap(t, x); down(t); } }
void up(int x) { while(x / 2 && h[x / 2] > h[x]) { heap_swap(x / 2, x); x >>= 1; } }
int main() { int n, m = 0; scanf("%d", &n); while (n -- ) { char op[5]; int k, x; scanf("%s", op); if (!strcmp(op, "I")) { scanf("%d", &x); cnt ++ ; m ++ ; ph[m] = cnt, hp[cnt] = m; h[cnt] = x; up(cnt); } else if (!strcmp(op, "PM")) printf("%d\n", h[1]); else if (!strcmp(op, "DM")) { heap_swap(1, cnt); cnt -- ; down(1); } else if (!strcmp(op, "D")) { scanf("%d", &k); k = ph[k]; heap_swap(k, cnt); cnt -- ; up(k); down(k); } else { scanf("%d%d", &k, &x); k = ph[k]; h[k] = x; up(k); down(k); } } }
|