通常我们使用的二叉堆,是用一个数组实现的完全二叉树,对于查询有O(1)复杂度,对于插入、删除有O(logn)复杂度
而且常数比较小,是一个比较优秀的数据结构
但是。
当我们需要合并两个堆的时候,用普通的二叉堆就显得吃力了,时间复杂度达到log(n+m)
这个时候可并堆这种数据结构就出现了。而在其中,尤以左偏树代码复杂度和时间复杂度综合得比较优秀
左偏树
在介绍左偏树之前,得先引入一个叫距离(d)的概念:
在左偏树中,一个节点u的距离,等于u到它和叶子节点中最近的左右儿子不满的节点【也就是可插入的节点】的距离。
然后左偏树是这样定义的:
左偏树是左儿子距离不小于右儿子距离的二叉堆。
这样子有什么用呢?
当插入节点时,只需往右儿子插入,可降低插入的时间复杂度。
实现
首先每个节点这样声明:
struct LT{
int v,l,r,d;
LT() {l=r=d=0;}
}e[maxn];
左偏树的所有操作都是以合并操作为基础的:
对于根节点为u和v两个左偏树是这样合并的:
1、如果其中有空节点,直接返回另一个非空结点
2、选择节点值较小的作为根节点,然后合并根节点的右儿子和另一个节点【merge(root.r,v)】【递归】
3、维护根节点的距离。我们设空节点的距离为-1,那么根节点的距离=右儿子距离+1
C++代码:
int merge(int a,int b){
if(!a) return b;
if(!b) return a;
if(e[b].v<e[a].v) a^=b^=a^=b;
e[a].r=merge(e[a].r,b);
if(e[e[a].l].d<e[e