就是stl里的优先队列
堆是一棵完全二叉树
除了最后一层 上面所有节点都是满的 最后一层是从左到右排列

小根堆 每一个点都小于等于左右子节点的 根节点就是最小值
存储
根节点是1 x的左儿子是2x 右儿子是2x+1

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(x);up(x);//同理 不知大小关系直接down了在up

[堆排序] [c++]
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
//思路就是将序列建成堆结构 每一次输出堆顶
#include<bits/stdc++.h>
using namespace std;

const int N=100010;

int n,m;
int h[N].size;

void down(int u) //往下调整 up是往上调整
{
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; //经过操作t是u和其两个儿子里最小的
if(u!=t) //如果u不是三个节点里最小的
{
swap(h[u],h[t]);
down(t);//对交换前儿子节点的下标进行递归操作
}

}

void up(int u)
{
while(u/2 && h[u/2]>h[u] ) //由于向下取整 两个儿子除二就是父节点
{
swap(h[u],h[u/2]);
u/=2;
}
}


int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>h[i];
size=n;

for(int i=n/2;i;i--) down(i);//建堆 二分之n是从倒数第二层开始调整每一个点 保证每一次down的时候下面的两个儿子已经是堆了
while(m--)
{
cout<<h[1];//根节点是最小的 将其输出后用尾节点替换 再将尾节点删除 递归down
h[1]=h[size];
size--;
down(1);
}
}

I x 插入一个数x
PM 输出当前集合中最小值
DM 删除当前集合最小值(不唯一时删除最早插入的)
D k 删除第k个插入的数
C k x 修改第k个插入的数为x

[模拟堆] [c++]
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
#include<bits/stdc++.h>
using namespace std;

const int N=100010;

int n,m;
int h[N],size;
int ph[N],hp[N]; //ph[k]存第k个插入的数的下标 hp[q]存堆中下标为q的 点是第几个插入的点 ph与hp是类似于反函数的关系

//因为要准确知道第k个数 手写维护映射关系比较麻烦 直接新定义个swap
void heap_swap(int a,int b)
{
swap(ph[hp[a]],ph[hp[b]]); //a b是第a1 b1个插入的点 将第a1 b1个插入的数的下标交换
swap(hp[a],hp[b]);
swap(h[a],h[b]); //交换值

}

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);
}

}

void up(int u)
{
while(u/2 && h[u/2]>h[u] )
{
heap_swap(h[u],h[u/2]);
u/=2;
}
}


int main()
{
int n,m=0; // m表示第k个插入的数
cin>>n;
while(n--)
{
char op[10];
int k,x;
cin>>op;
if(!strcmp(op,"I"))
{
cin>>x;
size++;
m++;
ph[m]=size,hp[size]=m;
h[size]=x;
up(size); //插入是插到最后嘛 由下而上ip
}
else if(!strcmp(op,"PM")) cout<<h[1];
else if(!strcmp(op,"DM")) //删除堆顶
{
heap_swap(1,size);
size--;
down(1);
}
else if(!strcmp(op,"D")) //删除第k个插入的元素
{
cin>>k;
k=ph[k]; //第k个插入的数的下标
heap_swap(k,size);
size--;
down(k),up(k);
}

else //修改第k个插入的数
{
cin>>k>>x;
k=ph[k];
h[k]=x;
down(k),up(k);
}
}
return 0;
}


其实一般遇不到有这种映射关系的堆 只需普通up down就行了
但是这是为之后搜索内容做铺垫