其他分享
首页 > 其他分享> > 左偏树学习笔记

左偏树学习笔记

作者:互联网

一.概念

左偏树是具有左偏性质的堆有序二叉树,可类比二叉堆。

如果要合并两个集合,对于二叉堆来说,要一个一个的插入合并,时间复杂度为O(n);而左偏树的优越就在于可以合并两个集合,需O(logn)的复杂度。

至少维护4个信息:1.2.左右子树指针;3.键值(优先级);4.距离dist(离外界点最近的距离)。

这里的优先级我理解为插入的元素,比如说要维护一个小根堆,插入10和12,那么10的优先级肯定比12高(因为维护的是小根堆嘛);外界点指的是:一个节点i,当i的左子树或右子树为空,那么i就是外界点,假设j是i的父亲,有dist(i)=0,dist(j)=1;

 

二.操作

(1)合并

int merge(int x,int y)
{
    if(!x) return y;//其中一棵树为空,返回另一棵树
    if(!y) return x;
    if(key[y]<key[x]) swap(x,y);//假设维护小根堆,保证优先级x>y
    r[x]=merge(r[x],y);合并x右子树和y
    if(dist[r[x]]>dist[l[x]]) swap(r[x],l[x]);
    if(r[x]==0) dist[x]=0;
    else dist[x]=dist[r[x]]+1;
    return x;
}

(2)单点插入:将点看作一棵左偏树,就相当于合并操作。

(3)删除堆顶节点

int deletemin()
{
    int t=key[root];
    root=merge(l[root],r[root]);
    return t;
}

(4)构建一棵左偏树(利用队列)

void build()
{
    int head=1,tail=n;
    for(int i=1;i<n;i++)
    {
        int root=merge(que[head],que[head+1]);
        que[++tail]=root;
        head+=2;
    }
}

(5)删除任意已知节点

void delete(int x)
{
  int q=fa[x];
  int p=merge(l[x],r[x]);
  fa[p]=q;
  if(q&&l[q]==x) l[q]=p;  //若x是q的左儿子,把p接在q左边
  if(q&&r[q]==x) r[q]=p;
  while(q)
  {
    if(dist[r[q]]>dist[l[q]]) swap(l[q],r[q]);  //要满足左偏性质
    if(dist[r[q]]+1==dist[q]) return;
    dist[q]=dist[r[q]]+1;
    p=q;
    q=fa[p];
  }
}

标签:dist,int,笔记,学习,merge,return,root,左偏
来源: https://www.cnblogs.com/yhxnoerror/p/15880789.html