堆 基本定义 根节点存在1号位,x点的左儿子:2x
x点的右儿子:2x+1
基本操作 ==这五个操作通过down(x)和up(x)都可以实现==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void down (int u) { int t = u; if (u * 2 <= siz && h[u * 2 ] <h[t]) t = u * 2 ; if (u * 2 + 1 <= siz && h[u * 2 + 1 ] < h[t]) t = u * 2 + 1 ; if (u != t){ swap (h[u], h[t]); down (t); } } void up (int u) { while (u / 2 && h[u / 2 ] > h[u]){ swap (h[u / 2 ], h[u]); u /= 2 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 heap代表堆数组,size代表堆的大小 * 插入一个数 将x插到heap的最后一位,再up heap[++size] = x; up(size); * 求集合当中的最小值 小根堆的第一个点就是最小值 heap[1]; * 删除最小值 因为一维数组删掉尾结点很容易(只需要size--),所以可以将尾结点覆盖到头结点(也就是最小值),然后down heap[1] = heap[size];size--;down(1); * 删除任意一个元素 同上。因为不知道heap[k]变大还是变小,也不需要判断,直接down和up就行(只会执行一个) heap[k] = heap[size];size--;down(k);up(k); * 修改任意一个元素 同上 heap[k] = x;down(k);up(k);
例题1.堆排序 1 2 3 4 5 6 7 8 9 10 11 12 13 输入一个长度为 n 的整数数列,从小到大输出前 m 小的数。 输入格式 第一行包含整数 n 和 m。 第二行包含 n 个整数,表示整数数列。 输出格式 共一行,包含 m 个整数,表示整数数列中前 m 小的数。 数据范围 1≤m≤n≤105, 1≤数列中元素≤109
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 #include <iostream> #include <algorithm> using namespace std;const int N = 1e5 + 10 ;int n, m;int h[N], siz;void down (int u) { int t = u; if (u * 2 <= siz && h[u * 2 ] <h[t]) t = u * 2 ; if (u * 2 + 1 <= siz && h[u * 2 + 1 ] < h[t]) t = u * 2 + 1 ; if (u != t){ swap (h[u], h[t]); down (t); } } int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cin>>n>>m; for (int i = 1 ; i <= n; i ++) cin>>h[i]; siz = n; for (int i = n / 2 ; i; i--) down (i); while (m--){ cout<<h[1 ]<<" " ; h[1 ] = h[siz]; siz --; down (1 ); } return 0 ; }
例题2.模拟堆 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 维护一个集合,初始时集合为空,支持如下几种操作: 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≤105 −109≤x≤109 数据保证合法。
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 #include <iostream> #include <algorithm> #include <string.h> using namespace std;const int N = 1e5 + 10 ;int ph[N], hp[N];int h[N], siz;int n, m;void heap_swap (int a, int b) { swap (ph[hp[a]], ph[hp[b]]); swap (hp[a], hp[b]); swap (h[a], h[b]); } void down (int u) { int t = u; if (2 * u <= siz && h[2 * u] < h[t]) t = 2 * u; if (2 * u + 1 <= siz && h[2 * u + 1 ] < h[t]) t = 2 * u + 1 ; if (t != u) { heap_swap (u, t); down (t); } } void up (int u ) { while (u / 2 && h[u / 2 ] > h[u]) { heap_swap (u / 2 , u); u /= 2 ; } } int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cin >> n; while (n--) { char op[10 ]; int k, x; cin >> op; if (!strcmp (op, "I" )) { cin >> x; siz ++; m++; ph[m] = siz, hp[siz] = m; h[siz] = x; up (siz); } else if (!strcmp (op, "PM" )) cout << h[1 ] << endl; else if (!strcmp (op, "DM" )) { heap_swap (1 , siz); siz--; down (1 ); } else if (!strcmp (op, "D" )) { cin >> k; k = ph[k]; heap_swap (k, siz); siz--; down (k), up (k); } else { cin >> k >> x; k = ph[k]; h[k] = x; down (k), up (k); } } return 0 ; }