手写堆
堆的存储:一维数组,定义数组h[10],h[1]为堆顶,其中h[x]的左节点为h[2x],右节点为h[2x+1]。
size:表示堆的大小
heap:表示堆
ph[k]:存储第k个插入的点在堆中的位置
hp[k]:存储堆中下标是k的点是第几个插入的
建堆(O(n)):
for (int i = n / 2; i; i -- ) down(i);
堆的操作:
1,down(x){ }(当堆中一个数变大,将其下沉)
void down(int u)
{
int t = u;
if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t)
{
heap_swap(u, t);
down(t);
}
}
2,up(x){ }(当堆中一个数变大,将其上浮)
void up(int u)
{
while (u / 2 && h[u] < h[u / 2])
{
heap_swap(u, u / 2);
u >>= 1;
}
}
交换两个点,及其映射关系
void heap_swap(int a, int b)
{
swap(ph[hp[a]],ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
堆的应用:
1,插入一个数:
在堆的最后插入一个元素,将元素调整至合适位位置:heap[++ size] = x; up(size);
2,求集合中的最小值:
堆中第一个数一定最小:heap[1];
3,删除最小值(堆顶):
先用堆的最后一个元素覆盖堆顶,再删除最后一个元素,
最后再维护堆(将覆盖后的堆顶下沉)。
heap[1] = heap[size]; size -- ; down(1);
4,删除任意一个元素:
同(3)注:heap[k]的值会有增减不变三种情况,
但up&down只会执行一种所以这里可以down&up都写。
heap[k] = heap[size]; size -- ; down(k); up(k);
5,修改任意一个元素:
同(4)
heap[k] = x; down(k); up(k);
结合以下题目:
模拟堆:
题干:
维护一个集合,初始时集合为空,支持如下几种操作:
- 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≤1051≤N≤105
−109≤x≤109−109≤x≤109
数据保证合法。
输入样例:
8
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM
输出:
-10
6
代码模板:
#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 a, int b)
{
swap(ph[hp[a]],ph[hp[b]]);
swap(hp[a],hp[b]);
swap(h[a],h[b]);
}
//down操作
void down(int u)
{
int t=u;
if(u*2<=cnt&&h[u*2]<h[t]) t=u*2;
if(u*2+1<=cnt&&h[u*2+1]<h[t]) t=u*2+1;
if(u!=t)
{
heap_swap(u,t);
down(t);
}
}
//up操作
void up(int u)
{
while(u/2&&h[u]<h[u/2])
{
heap_swap(u,u/2);
u>>=1;
}
}
//
int main()
{
int n,m=0;
scanf("%d",&n);
while(n--)
{
char op[5];
int k,x;
scanf("%s",op);
//操作I
if(!strcmp(op,"I"))
{
scanf("%d",&x);
cnt++;
m++;
ph[m]=cnt,hp[cnt]=m;
h[cnt]=x;
up(cnt);
}
//操作PM
else if(!strcmp(op,"PM"))
printf("%d\n",h[1]);
//操作DM
else if(!strcmp(op,"DM"))
{
heap_swap(1,cnt);
cnt--;
down(1);
}
//操作D
else if(!strcmp(op,"D"))
{
scanf("%d",&k);
k=ph[k];
heap_swap(k,cnt);
cnt--;
up(k);
down(k);
}
//操作C
else
{
scanf("%d%d",&k,&x);
k=ph[k];
h[k]=x;
up(k);
down(k);
}
}
return 0;
}