Splay入门详解

Splay入门详解

写在前面

听说平衡树是一种强大的数据结构,听同年级或高年级大佬们讲起来也感觉很牛笔的亚子,而最近XC又叫我们去学习一下 L C T LCT LCT!?
又因为 S p l a y Splay Splay是学习 L C T LCT LCT的基础,而且又比较脍炙人口,于是我便学了一下,经过一个白天的努力,也终于是学会了一点皮毛。
为了加深我对 S p l a y Splay Splay的理解,把网上一些讲得有点模糊的知识点给没看懂的同学讲解清楚,于是我就写了这篇博客,保证大家都可以入门 (不行也别怪我哦)

Splay是神马东东?

给出百度的解释: S p l a y Splay Splay
下面我用简单易懂的语言来简单介绍一下:
首先 S p l a y Splay Splay是一棵二叉查找树,之后 S p l a y Splay Splay又可以通过各种骚操作(主要是旋转操作)使得整棵树仍然满足二叉查找树的性质,并且保持相对的平衡不至于退化成链而大大提高复杂度,这个神奇的东西是由Daniel Sleator 和 Robert Tarjan这两位大神发明的
二叉查找树又是神马呢?
首先他肯定是一棵二叉树 (废话)
而且这棵树有一个非常厉害的性质:能够在这棵树上查询到的节点一定满足:左子树任意节点的值 < < <根节点的值 < < <右子树任意节点的值

例题 LOJ #104.普通平衡树

这道题的题目大意就是有n个操作,一共有6种操作,对应1~6编号:
1.插入 x x x
2.删除 x x x数(若有多个相同的数,因只删除一个)
3.查询 x x x数的排名(排名定义为比当前数小的数的个数+1)
4.查询排名为 x x x的数
5.求 x x x的前驱(前驱定义为小于 x x x,且最大的数)
6.求 x x x的后继(后继定义为大于 x x x,且最小的数)
之后对于3,4,5或6操作的结果进行输出

详解Splay操作

接下来我们来结合我的解析和代码对Splay的操作进行了解

变量

int n;//操作个数
int son[N][2];//该节点的左/右儿子的编号,0表示左儿子,1表示右儿子
int fa[N];//该父亲节点
int cnt;//节点的总数
int tot[N];//该节点权值出现的次数
int size[N];//以该节点为根的子树大小
int root;//根节点
int val[N];//该节点的权值

三个最基本的操作

  • 改变节点在树中的位置之后,更新该节点的 s i z e size size值: m a i n t a i n ( x ) maintain(x) maintain(x)
inline void maintain(int x) {
   size[x]=size[son[x][0]]+size[son[x][1]]+tot[x];}
//左子树的大小加上右子树的大小在加上该节点的值的个数
  • 判断该节点是父亲的左儿子还是右儿子: g e t ( x ) get(x) get(x)
inline bool get(int x) {
   return x==son[fa[x]][1];}
//如果跟右儿子相等则返回1,否则返回0
  • 销毁该节点: c l e a r ( x ) clear(x) clear(x)
inline void clear(int x) {
   size[x]=fa[x]=son[x][0]=son[x][1]=tot[x]=val[x]=0;}
//该节点的所有数据全部清除

旋转操作 rotate(x)

这个操作是为了使 S p l a y Splay Splay保持平衡而产生的,其本质是将某个节点上移一个位置
旋转操作需要保证:

  • 整棵 S p l a y Splay Splay 中序遍历(就是先遍历左儿子,再遍历根节点,最后遍历右儿子) 的顺序不变(为了不破坏二叉查找树的性质)
  • 旋转后受到影响的节点所维护的信息仍然是正确有序的
  • r o o t root root必须变成旋转过后的根节点

S p l a y Splay Splay中的旋转分为左旋右旋两种,如图所示:
在这里插入图片描述
我们来分析一下旋转具体操作(这里以右旋为例子,假设需要旋转的节点为 x x x,其父亲为 y y y,如果是左旋则所有方向相反):

  1. x x x的右儿子交给 y y y当它的左儿子,将 x x x的右儿子的父亲赋值为 y y y
  2. y y y赋值为 x x x</
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值