Splay的几种操作(代码)

1.右旋(zig)

void _zig(int x)
{
	int y,z;
	y=pr[x];
	z=pr[y];
	if(z==0)
	    root=x;
	else if(ls[z]==y)
	    ls[z]=x;
	else 
	    rs[z]=x;
	pr[x]=z;
	pr[y]=x;
	ls[y]=rs[x];
	pr[rs[x]]=y;
	rs[x]=y;
	size[x]=size[y];
	size[y]=size[ls[y]]+size[rs[y]]+1;
}
2.左旋(zag)

void _zag(int x)
{
	int y,z;
	y=pr[x];
	z=pr[y];
	if(z==0)
	    root=x;
	else if(ls[z]==y)
	    ls[z]=x;
	else 
	    rs[z]=x;
	pr[x]=z;
	pr[y]=x;
	rs[y]=ls[x];
	pr[ls[x]]=y;
	ls[x]=y;
	size[x]=size[y];
	size[y]=size[ls[y]]+size[rs[y]]+1;
}
3.splay旋转(平衡性较好的一种写法)
void _splay(int x)
{
    int j;
    while(x!=root)
    {
        j=pr[x];
        if(j==root)
        {
            if(x==ls[j])_zig(x);
            else _zag(x);
        }
        else 
        {
            if(j==ls[pr[j]])
            {
                if(x==ls[j]){_zig(j);_zig(x);}
                else {_zag(x);_zig(x);}
            }
            else 
            {
                if(x==rs[j]){_zag(j);_zag(x);}
                else {_zig(x);_zag(x);}
            }
        }
    }
}
4.插入(insert)(记了左右子节点数量的一种写法,便于查找第k小)
void _insert(int key)
{
	int i=root;
	if(size[i]==0)
	{
		data[i]=key;
		pr[i]=0;
		size[i]=1;
		tot++;
		return;
	}
	if(_find(key)==-1)
	{
    	while(true)
	    {
		    if(key<data[i])
		    {
			    if(ls[i]!=0)
			    {
			    	size[i]++;
			        i=ls[i];
			    }
		    	else 
		    	{
			    	pr[tot]=i;
				    data[tot]=key;
				    ls[i]=tot;
				    size[tot]=1;
				    size[i]++;
				    tot++;
				    return;
		    	}
	    	}
		    else if(key>data[i])
		    {
		    	if(rs[i]!=0)
		    	{
		    		size[i]++;
		    	    i=rs[i];
		    	}
		     	else 
		    	{
			    	pr[tot]=i;
			    	data[tot]=key;
			    	rs[i]=tot;
			    	size[tot]=1;
			    	size[i]++;
			    	tot++;
			    	return;
		    	}
	    	}
	    	else
	    	{
	    		_splay(i);
	    		return;
	    	}
	    }
	}
}
5.删除(del)
void _del(int key)
{
	int x,y=0,z=0;
	x=_find(key);
	if(x==-1)
	    return;
	_splay(x);
	y=_findpre(x);
	if(y!=0)
	{
		_splay(y);
		rs[y]=rs[x];
		pr[rs[x]]=y;
		size[y]--;
		root=y;
	}
	else
	{
		z=rs[x];
		pr[z]=0;
		root=z;
	}
}
6.查找(find)
int _find(int key)
{
	int i=root;
	while(i!=0)
	{
		if(key<data[i])
		    i=ls[i];
		else if(key>data[i])
		    i=rs[i];
		else 
		    return i;
	}
	return -1;
}
7.找前驱(findpre)
int _findpre(int x)
{
	int i;
	if(x!=root)
	    _splay(x);
	i=ls[x];
	while(rs[i]!=0) i=rs[i];
	return i;
}
8.找后继(findnex)
int findnex(int key)//返回值为key的后继的下标
{
	int k=root,ans=0;
	while(k)
		if(key>data[k])k=rs[k];
		else{
			ans=k;
			k=ls[k];
		}
	return ans;
}
9.找第k小数(findkth)

int _findkth(int x)
{
    int i=root;
    while(i!=0)
    {
        if(ls[i]!=0&&x<=size[ls[i]])
		    i=ls[i];
        else if(x>size[ls[i]]+1)
        {
            x-=size[ls[i]]+1;
            i=rs[i];
        }
        else
            return data[i];
    }
    if(i==0)
	    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值