这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间

后一半的博客地址:【传送门】

前言骚话

为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉模板题和文艺平衡树。
这一片博客就是写了跟我之前有相同处境的小伙伴们。我尽可能的写的简单一点,在带一点自己学习时候的心得和总结。(难免会有一点冗长,大佬勿喷)
吐槽:splay=cosplay=slay(滑稽)
如要转载,请注明出处和作者:https://www.cnblogs.com/chhokmah/p/10577166.html 。作者chhokmah(扒我的图片的时候要和我说一声,不要把水印删掉了,不要吐槽我的图非常丑陋QwQ)。

简要介绍一下splay

splay(伸展树)是一种二叉搜索树。所谓二叉搜索树,又称作二叉查找树,二叉排序树。
二叉搜索树具有以下的性质:如果左树非空,那么左树中所有的节点所代表的权值都小于根节点的权值。同理右子树中所有节点所代表的权值都大于根节点的权值。和二分查找非常的相似,没错就是参照了二分的思路实现了这种数据结构。(话说二分真的好厉害呀QwQ)。
以下这个图片上显示的就是一棵简单的二叉搜索树,接下来我们都用BST(Binary Search Tree)来简写二叉搜索树。

但是还有一个非常极端的情况,请看下图:

上图描述就是所有树形结构都必须要解决的共同问题,退化成一条链,虽然还是保持的是BST的性质,但是我们查询的复杂度就会变成了\(O(n)\),那么很多BST的操作都可以解决这个问题,比如说treap的随机标记,还有我们今天要讲的splay伸展操作。


话说这东西又是tarjan大佬做出来的,太强了。
来自百度百科的描述:它由丹尼尔·斯立特Daniel Sleator 和 罗伯特·恩卓·塔扬Robert Endre Tarjan 在1985年发明的。%%% orz。


update 2019/3/23
感觉还是要明确一下splay的结构体

struct node {int val, fa, cnt, sz, ch[2];void init(int x, int ft) {fa = ft;val = x;ch[1] = ch[0] = 0;sz = cnt = 1;}
}

分别解释一下,val表示的是当前节点代表的权值,fa表示这个节点的父亲节点,cnt表示有多少相同的权值,因为在BST中不存在相同的节点,那么就需要把相同的权值都放到相同的节点内,ch[0]和ch[1]分别表示左儿子和右儿子。


Q:为什么很多BST要有旋转(rotate)操作?
A:为了防止出现链的情况,我们需要在保证BST原来的性质的条件下,将BST的结构改掉,这样就不会有链的情况了。
比如说看一下下面这种图片:(给出的样例是Nod是父亲的左儿子,Fa为祖父的左儿子)

天哪我放的有一点快了,但是不影响阅读。我们就将上图左图当做我们现在的BST。
根据BST的性质,容易得出Gf>A>Fa>C>Nod>B。为了改造BST的结构,那么我们就考虑将Nod(当前节点)旋转到父亲节点Fa的位置。
Nod和他的Fa的关系是Nod<Fa,那么如果要让Nod做Fa的父亲的位置,那么Fa一定是Nod的右节点。
因为Fa变成了Nod的一个子节点,那么Gf(祖父节点)的左儿子就变成了Nod节点,说的普遍一点,就是Nod代替了原来自己父亲的位置(大义灭亲)。
再回到Nod原来的子节点,因为维护二叉的性质,那么我们需要让Nod的其中一个儿子变成Fa的儿子。
我们选择了C号节点,因为原来的Nod节点的有儿子就是C节点,而现在被Fa代替掉了。因为C是Nod的子节点,那么C<Fa,因此,C号节点就变成了Fa的左节点,那么原来的B号节点就不需要移动了。
旋转之后得到的就是上面图片的右图,重新审核一下我们图的大小关系。Gf>A>Fa>C>Nod>B,和原来的树是一样的顺序,而且也将原来的那个链的结构改掉了,维护了BST的复杂度。完美؏؏☝ᖗ乛◡乛ᖘ☝؏؏。
还有更多的旋转的情况,以下三种大家可以推一下对照一下是不是这样的:
情况二:Nod是父亲的右节点,Fa是Gf的左节点

情况三:Nod是父亲的左节点,Fa是Gf的右节点

情况四:Nod是父亲的右节点,Fa是Gf的右节点


作为一个合格oier,代码还是需要写的。我们先整理一下rotate旋转操作的思路吧。
先针对nod节点,我们可以发现nod节点在每一幅图中都有一个节点是不变的,反观我们之前推导的Fa变成nod节点的其中一个子节点可得,nod是fa的哪一个节点,那么nod的哪一个节点就不会改变。另外一个节点就变成了fa的另一个节点。
那么nod节点本身就会变成Gf的一个子节点。
总结一下过程:
1.nod变到原来fa的位置
2.fa变成了 nod原来在fa的 相对的那个儿子
3.fa的非nod的儿子不变 nod的 nod原来在fa的 那个儿子不变
4.nod的 nod原来在fa的 相对的 那个儿子 变成了 fa原来是nod的那个儿子。

给出代码

void rotate(int nod) {int fa = tr[nod].fa, gf = tr[fa].fa, k = tr[fa].ch[1] == nod;//fa和gf都是上面提到的意思tr[gf].ch[tr[gf].ch[1] == fa] = nod;//先把fa原来的位置变成nodtr[nod].fa = gf;//更新父亲tr[fa].ch[k] = tr[nod].ch[k ^ 1];//nod的与nod原来在fa的相对的那个儿子变成fa的儿子tr[tr[nod].ch[k ^ 1]].fa = fa;//更新父亲tr[nod].ch[k ^ 1] = fa;//nod的 与nod原来相对位置的儿子变成 fatr[fa].fa = nod;//更新父亲}

接下来就是splay操作,沃觉得splay操作有两个用处:

  • 将某一个节点提到某一个位置
  • 维护树的复杂度,这个复杂度指的是查询等其他操作时的时间复杂度。

我们思考一个问题,如果我们需要把一个节点提到某一个需要的位置,也许就是根节点,需要怎么操作。
第一次我想到的就是,不断向上旋转,但是这样是错误的,会T到爆炸。
请看一下下面的图:(这个图实在是太丑了)

还有一个动态图

把一个点双旋到根,可以使得从根到它的路径上的所有点的深度变为大约原来的一半,其它点的深度最多增加2
很明显,我们旋转过后,虽然节点编号之间的顺序发生了变化,但是这条链还依旧是存在的,动态图中更加明显。
为了解决这个问题,我们需要修改一下splay操作,加入判断是否儿子节点是否相同。

  • nod和fa分别是fa和gf的同一个儿子
  • nod和fa不是fa和gf的同一个儿子

那么对于第一种操作就是先旋转fa,在旋转nod
第二种操作是旋转两遍nod。

代码说话

void splay(int nod, int goal) {//goal表目标节点while (tr[nod].fa != goal) {int fa = tr[nod].fa, gf = tr[fa].fa;if (gf != goal) {if ((tr[gf].ch[0] == fa) ^ (tr[fa].ch[0] == nod)) rotate(nod);else rotate(fa);}rotate(nod);//再次旋转}if (goal == 0) rt = nod;//如果目标节点是0,那么就把根节点变成nod节点
}

转载于:https://www.cnblogs.com/chhokmah/p/10577166.html

「平衡树splay」学习笔记#1相关推荐

  1. 「C++: Eigen」学习笔记

    参考链接:Eigen Doc Home Eigen介绍 Eigen是一个C++线性代数模板库,包括矩阵,向量,数值求解器以及相关算法. Eigen支持任意矩阵大小和矩阵类型.标准数据类型.矩阵分解.几 ...

  2. 平衡树(splay)学习笔记(详细,从入门到精(bao)通(ling))(持续更新)

    前言 在前几天军训站军姿的时候胡思乱想,突然明白了splay的本质 KMP学习笔记后又一篇字数上万的题解- 前置技能--二叉搜索树 首先来看一个最简单的问题: 你需要维护一个数据结构,资磁这些操作: ...

  3. AI正在模仿人类大脑!2021年10篇顶会论文:大脑也在「无监督」学习

    编辑:桃子 小咸鱼 [导读]神经科学会成为人工智能「超进化」的关键吗?只要模拟大脑,神经网络就可以获得相似或相同的智能.近日,神经科学家Patrick Mineault就2021年无监督学习的大脑模型 ...

  4. 小师弟肝了七天七夜,东半球最全「后台开发」学习路线出炉

    点击上方"五分钟学算法",选择"星标"公众号 重磅干货,第一时间送达 来源:编程指北 前言 这一篇的主题是「Linux C/C++ 服务器/后台开发学习路线」. ...

  5. 「西瓜书」阅读笔记——决策树

    决策树是机器学习中一类非常著名的算法,它模拟人们在解决一个决策问题时的思考方式,因此具有非常好的可解释性.一般来说,一个训练好的决策树模型可以转化成一系列的"if-then"语句, ...

  6. 熬了几个大夜,学完一套985博士总结的「卷积神经网络、目标检测、OpenCV」学习笔记(20G高清/PPT/代码)...

    AI 显然是最近几年非常火的一个新技术方向,从几年前大家认识到 AI 的能力,到现在产业里已经在普遍的探讨 AI 如何落地了. 我们可以预言未来在很多的领域,很多的行业,AI 都会在里边起到重要的作用 ...

  7. 「欧拉定理」学习笔记(费马小定理)

    欧拉定理:对于互质的两个正整数$a, n$,满足$a^{φ(n)} ≡ 1\  (mod\ n)$ 证明: 设集合$S$包含所有$n$以内与$n$互质的数,共有$φ(n)$个:$$S = \{ x_1 ...

  8. case when then else多个条件_CentOS「linux」学习笔记24:if和case多个条件判断

    ​linux基础操作:主要介绍了if和case判断多个条件. 多条件判断语句if例子: 例子1:if [ $1 -ge 60 ];then echo "接收的参数位1的值大于等于60&quo ...

  9. linux挂载硬盘_CentOS「linux」学习笔记12:磁盘管理、分区挂载卸载操作

    linux基础操作:主要介绍了磁盘管理.分区挂载卸载操作. 特别说明linux中磁盘表现形式: IDE硬盘在linux中表示方式为"hdx".SCSI硬盘在linux中表示方式为& ...

  10. centos 卸载_CentOS「linux」学习笔记12:磁盘管理、分区挂载卸载操作

    linux基础操作:主要介绍了磁盘管理.分区挂载卸载操作. 特别说明linux中磁盘表现形式: IDE硬盘在linux中表示方式为"hdx".SCSI硬盘在linux中表示方式为& ...

最新文章

  1. 条件选择结构:星期计划(switch)
  2. linux shell 运算符 | || () {}
  3. addr2line命令
  4. 结构型模式:外观模式
  5. 查看回滚事物sql_卧槽:这款 SQL自动检查神器,吊炸天的功能,真TMD多!!
  6. STL笔记(4)关于erase,remove
  7. 【UOJ#246】套路(动态规划)
  8. Dubbo(一)之简介
  9. java连接mysql实现增删改查_JDBC之Java连接mysql实现增删改查
  10. .net上传大文件不成功
  11. BZOJ2658 ZJOI2012 小蓝的好友(treap)
  12. aliyun阿里云视频直播播放器代码
  13. 微信小程序开发详细步骤
  14. 【Format】ASF/WMV 文件格式解析
  15. 无线射频专题《IEEE 802.11协议讲解4@可调参数,性能与兼容性考虑》
  16. 2016 杭州云栖大会随笔
  17. html2canvas.js 截屏微信头像不显示
  18. Docker入门到实践 (一) docker简介与安装、常用命令讲解
  19. 任务定义的脑网络的内在连接模式可以个体化预测精神分裂症患者的认知症状维度
  20. 【报错解决】CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/main/nux-64

热门文章

  1. Gradle方式构建Java多项目
  2. SQL Server 字符串拆分
  3. Redis应用(三)——在非框架中的应用
  4. JS实现Sql语句格式化效果
  5. (day 24 - 广度优先搜索 )剑指 Offer 32 - I. 从上到下打印二叉树
  6. Thread中的静态代理
  7. 从linux服务器上取文件,简介从Linux服务器上远程获取文件的几种方法
  8. python requests text content_对python requests的content和text方法的区别详解
  9. java中 t无法对齐,java – 即使X应匹配T,也无法将X转换为T?
  10. pythonmkdir语法错误_转--python使用mkdir函数出现错误WindowsError:[Error3]