码迷,mamicode.com
首页 > 其他好文 > 详细

Splay

时间:2020-01-22 22:19:03      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:else   次数   mat   中序   pre   spl   父节点   技术   ==   

二叉查找树,对于任意一个节点,该节点的关键码大于它的左子树中任意节点的关键码,该节点的关键码小于它的右子树中任意节点的关键码,且没有键值相等的点

二叉查找树的中序遍历是一个关键码单调递增的节点序列

数组及变量

\(fa[i]:\) 节点\(i\)的父节点

\(son[i][0]:\) 节点\(i\)的左儿子

\(son[i][1]:\) 节点\(i\)的右儿子

\(key[i]:\) 节点\(i\)的关键字

\(siz[i]:\) 以节点\(i\)为根的子树元素个数

\(cnt[i]:\) 节点\(i\)所表示的元素的出现次数

\(tot:\) 共有多少元素

\(root:\) 树的根

函数

\(check:\) 判断节点\(x\)是它父亲的左儿子还是右儿子

\(pushup:\) 更新节点\(x\)\(siz\)

\(rotate:\) 将是左儿子的右旋,是右儿子的左旋

技术图片

\(splay :\) 进行伸展,不断\(rotate\)直到达到目标状态

\(insert:\) 插入一个值

\(find:\) 查找\(x\)的位置,并将其旋转到根节点

\(rnk:\) 查询\(x\)的排名

\(val:\) 查询排名为\(x\)的数

\(get:\) \(k=0\)时,求\(x\)的前驱,\(k=1\)时,求\(x\)的后继

\(del:\) 删除为\(x\)的数

\(code\)

bool check(int x)
{
    return ch[fa[x]][1]==x;
}
void pushup(int x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],k=check(x);
    ch[z][check(y)]=x,fa[x]=z;
    ch[y][k]=ch[x][k^1],fa[ch[x][k^1]]=y;
    ch[x][k^1]=y,fa[y]=x;
    pushup(y),pushup(x);
}
void splay(int x,int goal)
{
    for(int y;fa[x]!=goal;rotate(x))
        if(fa[y=fa[x]]!=goal)
            rotate(check(x)^check(y)?x:y);
    if(!goal) root=x;
}
void insert(int x)
{
    int p=root,pre=0;
    while(p&&key[p]!=x)
    {
        pre=p;
        p=ch[p][key[p]<x];
    }
    if(p) cnt[p]++;
    else
    {
        p=++tot;
        if(pre) ch[pre][key[pre]<x]=p;
        fa[p]=pre;
        key[p]=x;
        cnt[p]=siz[p]=1;
        ch[p][0]=ch[p][1]=0;
    }
    splay(p,0);
}
void find(int x)
{
    int p=root;
    while(ch[p][key[p]<x]&&x!=key[p])
        p=ch[p][key[p]<x];
    splay(p,0); 
}
int rnk(int x)
{
    find(x);
    return siz[ch[root][0]];
}
int val(int x)
{
    int p=root;
    x++;
    while(1)
    {
        if(ch[p][0]&&x<=siz[ch[p][0]]) p=ch[p][0];
        else
        {
            int tmp=siz[ch[p][0]]+cnt[p];
            if(x<=tmp) return key[p];
            x-=tmp;
            p=ch[p][1];
        }
    }
}
int get(int x,int k)
{
    find(x);
    int p=root;
    if(key[p]>x&&k) return p;
    if(key[p]<x&&!k) return p;
    p=ch[p][k];
    while(ch[p][k^1]) p=ch[p][k^1];
    return p;
}
void del(int x)
{
    int pre=get(x,0),nxt=get(x,1);
    splay(pre,0),splay(nxt,pre);
    int d=ch[nxt][0];
    if(cnt[d]>1)
    {
        cnt[d]--;
        splay(d,0);
    }
    else 
    {
        ch[nxt][0]=0;
        pushup(nxt),pushup(root);
    }
}

......

insert(inf),insert(-inf);

insert(a)
del(a)
rnk(a)
val(a)
key[get(a,0)]
key[get(a,1)]

Splay

标签:else   次数   mat   中序   pre   spl   父节点   技术   ==   

原文地址:https://www.cnblogs.com/lhm-/p/12229482.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!