您的位置:首页 > 其它

左偏树(可并堆)详解及有关模板

2017-09-03 21:11 239 查看
这几天搞了几道左偏树的题,主要是开阔眼界,堆还能这样写,下面详细讲解一下左偏树的特点及其应用。

首先从可并堆的定义讲起:

可并堆,就是一种支持合并的堆,如果用普通的二叉堆来实现合并操作,则O(n)的合并时间复杂度是一个瓶颈,这是就要引入左偏树(Leftist Tree),其实二项堆和Fibonacci堆也是很优秀的可并堆,这里只讲其中的左偏树。

左偏树定义:

左偏树是一种可并堆的实现,左偏树是一棵二叉树,除了左右子树指针外,还有键值和dist距离,距离则是这样定义的:

首先定义节点i为外节点当且仅当节点i的左子树或右子树为空,节点i的距离dist[i]是在节点i到它的子树中,最近的外节点所经过的边数。如果节点i为外节点,则它的距离为0,如果节点i为空节点,则它的距离为-1。

左偏树满足的性质:

性质1、由大小根堆来定,即二叉堆的性质。

性质2、节点左子节点的距离不小于右子节点的距离(左偏树名称的由来)

性质3、节点距离等于它的右子节点的距离加1

然后就有一些引理和定理:

引理1:若左偏树的距离为一定值,则节点数最少的左偏树是完全二叉树

定理1:若一棵左偏树的距离为k,则这棵左偏树至少有2^k+1-1个节点

从而可以得出性质4:一棵N个节点的左偏树距离最多为下取整log(N+1) -1。

接下来是合并操作,很好理解,贴上模板差不多就知道了

int merge(int x,int y){
if(!x) return y;
if(!y) return x;
if(heap[x].key>heap[y].key) swap(x,y);
heap[x].r=merge(heap[x].r,y);
if(heap[heap[x].r].key>heap[heap[x].l].key) swap(heap[x].l,heap[x].r);
heap[x].dist=heap[heap[x].r].dist+1;
return x;
}

删除操作很简单,比如删除节点i,只要将左子树和右子树合并,然后修改它们的父亲即可。
inline void erase(int u){
int l=heap[u].left,r=heap[u].right;
heap[u].key=-1;heap[l].fa=0;heap[r].fa=0;
merge(l,r);
return;
}

两个主要操作已经讲好了,其他操作都是基于这两个操作的,就不加赘述,详细的可以见国家集训队论文2005黄源河的论文,讲的很好懂。
接下来就是多做题了,明白了定义模板做题也是必要的O(∩_∩)O哈哈~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: