splay的一些基本操作,保证一遍看懂!

本蒟蒻第一篇blog,写的不好请见谅!
所谓splay就是将一个节点旋转到顶点的操作,而splay这种数据结构就是为了保证树的平衡而做的

什么是树的平衡呢?
首先我们说的树是二叉搜索树,也就是大小分别是左中右从小到大(当然也可以为了需要变成右中左),并且满足整颗左子树全部小于根节点,右子树全部大于根节点。这种二叉搜索树的好处就在于每一次查询耗费的时间仅为层数,不用把整个数组都遍历一遍,而且从中删除数字也非常容易
二叉搜索树
但是缺点也是很明显的
这里写图片描述

所以我们引进了一种二叉搜索树的升级版——平衡树
平衡树是一棵二叉搜索树。它除了具有二叉搜索树的全部特征之外,还具有一个关键性的特征:“平衡”,即任意节点的左右子树高度差不超过1。
这个特性决定了它在面对特殊数据(例如那种专门卡普通二叉搜索树的数据)时,能够非常稳定的解决,只是牺牲了一些时间复杂度常数,但是基本不会被卡掉。

平衡树有非常多的实现方式,包括splay,treap(不是严格的平衡树),替罪羊树,红黑树,sbt(size balanced tree即严格平衡),AVL(后面三种本蒟蒻都不会)等
由于treap旋转丑陋,代码量较大,而且万一随机数被卡,那么得不偿失,所以考场上推荐使用我们的优美的——splay

splay的特点是非常稳定,但是常数巨大,因为不论什么操作每次都要进行splay

一个treap需要包含:val, rank(随机数),l, r
splay中包含:val, son[1] (左右孩子), fa(为了方便把父亲带上)

struct ppp{
    int son[2], fa, siz, val, num;
}s[300001];

num是一个小小的优化,比如遇到两个相同的数我们就不分开成两个点存储,而是存成一个点,然后把num标成2

为了能够处理那种链状的结构
所以这里我们引进两种

旋转:

(其实和treap的旋转式一样的)
这里写图片描述
这里我们称被旋转的节点是被提上去的点(如作图为对5旋转,右图为对8旋转)

旋转可以维持二叉搜索树的性质但是可以使树变得平衡

int get(int x){
  return (s[s[x].fa].son[1] == x);}//返回这一点是左儿子还是右儿子

void rotate(int x)
{
    int f = s[x].fa, ff = s[f].fa, which = get(x);
    s[f].son[which] = s[x].son[which ^ 1];
    if(s[f].son[which]) s[s[f].son[which]].fa = f;
    s[f].fa = x;
    s[x].son[which ^ 1] = f;
    s[x].fa = ff;
    if(ff)
        s[ff].son[s[ff].son[1] == f] = x;
    update(f); update(x);
}

treap完成这一操作是基于再加一个关键字rank维护rank的二叉堆性质来实现的

而splay就是通过判断两种情况来执行的

情况1:

一个点p和他的父亲同为一边的儿子(如图同为左儿子)
此时应先rotate(p.fa), 再rotate(p)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值