堆的定义
这里的堆相当于C++的STL容器中的优先队列,形状为一棵完全二叉树
大根堆:对于每个节点的数值大于左右子树,堆顶元素为最大值
小根堆:对于每个节点的数值小于左右子树,堆顶元素为最小值
堆的存储方式(数组模拟)
堆的操作
1.插入一个数:heap[++ size] = x, up(size);
2.求集合当中的最值:heap[1]
3.删除最值:heap[1] = heap[size], size --, down(1);
4.删除任意一个元素:heap[k] = heap[size], size --, down(k), up(k);
5.修改任意一个元素:heap[k] = x, down(k), up(k);
模板 (小根堆):
void down(int u)
{
int t = u;//t存储最小值
if (u * 2 <= cnt && h[u * 2] < h[t]) t = 2 * u;
if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = 2 * u + 1;
if (u != t)
{
swap(u, t);
down(t);
}
}
void up(int u)
{
while (u / 2 && h[u / 2] > h[u])
{
swap(u / 2, u);
u /= 2;
}
}
Acwing模拟堆(映射)
思路:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int h[N], hp[N], ph[N];
//hp代表这是第几个插入的数
//ph[k]表示第k个插入的数在哪里
int sz; // 存储堆中元素个数
int cnt = 0; // 存储插入的所有数的个数
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 <= sz && h[2 * u] < h[t]) t = 2 * u;
if (2 * u + 1 <= sz && h[2 * u + 1] < h[t]) t = 2 * u + 1;
if (u != t)
{
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()
{
int n;
cin >> n;
while (n --)
{
string op;
cin >> op;
if (op == "I")
{
int x;
cin >> x;
cnt ++;
sz ++;
ph[cnt] = sz;
hp[sz] = cnt;
h[sz] = x;
up(sz);
}
else if (op == "PM")
{
cout << h[1] << endl;
}
else if (op == "DM")
{
heap_swap(1, sz);
sz --;
down(1);
}
else if (op == "D")
{
int k;
cin >> k;
k = ph[k];
heap_swap(k, sz);
sz --;
up(k);
down(k);
}
else if (op == "C")
{
int k, x;
cin >> k >> x;
k = ph[k];
h[k] = x;
down(k);
up(k);
}
}
}
Acwing838. 堆排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int h[N], s;
void down(int u)
{
int t = u;//三个点中的最小值对应的位置
if (2 * u <= s && h[2 * u] < h[t]) t = 2 * u;//若左儿子存在,并且u对应位置上的左儿子比当前位置上的值小,
if (2 * u + 1 <= s && h[2 * u + 1] < h[t]) t = 2 * u + 1;//若右儿子存在,将当前最小值与右儿子进行比较
if (t != u)//u位置所对应的值不是三个点中的最小值
{
swap(h[t], h[u]);//将u位置所对应的值与最小值进行交换
down(t);//继续递归,t = u为递归出口
}
}
int main()
{
int n, m;
scanf("%d%d",&n,&m);
for (int i = 1 ; i <= n; i ++ ) scanf("%d",&h[i]);
s = n;
for (int i = n / 2; i; i --) down(i);
while (m --)
{
printf("%d ",h[1]);
h[1] = h[s];
s --;
down(1);
}
}
如有错误,欢迎指正!!!