声明:这里的堆是二叉堆,不是斜堆,左偏树,斐波那契堆之类的**东西(我都不会啊!!)
二叉堆,是一棵完全二叉树
树的根称为堆顶
一个节点的子树为空或一个堆
左儿子比右儿子小或大(怎么高兴怎么来)
左右儿子都比父亲大或小
堆顶最大称为大根堆
堆顶最小称为小根堆
如“图”,这是一个小根堆:
1
/ \
2 3
/ \ /
3 4 4
图很烂,不要介意
堆有4个基本操作:
插入,删除,取堆顶,合并
取堆顶简单,不说了
合并要把一个堆全放进另一个里
普通堆是nlogn的复杂度
所以一般用左偏树
由于我不会不想说就不说了
插入:
为了让堆保持完全二叉树的性质,比如我要插个0,操作如下
先把0插在最下面
1
/ \
2 3
/ \ / \
3 4 4 0
然后发现不符合二叉堆性质
换一下
1
/ \
2 3
/ \ / \
3 4 0 4
还是不行,再换
1
/ \
2 0
/ \ / \
3 4 3 4
换
0
/ \
2 1
/ \ / \
3 4 3 4
这就对了
时间复杂度为O(logn)
删除:
好,现在我要把0删了
为了不影响其他数,只有叶子结点可以直接删除
0是根,不能直接删
所以,换
1
/ \
2 0
/ \ / \
3 4 3 4
换
1
/ \
2 3
/ \ / \
3 4 0 4
换
1
/ \
2 3
/ \ / \
3 4 4 0
换
这就可以删了
手打堆的代码太麻烦,本蒟蒻就懒得写了
STL:
priority_queue,优先队列,简称大根堆
push插入top堆顶pop删除堆顶
想用小根堆先变成负的再插,就行了
堆排序就是这样用的,全插进去再取出来
推荐几道题:
洛谷P3378,小根堆版子题,非常Easy
P1801黑匣子(有难度)
P2048,超级钢琴(谁愿做谁做,反正本蒟蒻完全不会)
P7078,贪吃蛇(要是做出来,恭喜你,可以进省队了)(CSP-S2020的题,我真F**K感谢CCF,提高组上黑题)
continue;