伸展树原理介绍

news2024/10/6 2:31:31

一 点睛

伸展树,也叫作分裂树,是一种二叉搜索树,可以在 O (logn ) 内完成插入、查找和删除操作。在任意数据结构的生命周期内执行不同操作的概率往往极不均衡,而且各操作之间有极强的相关性,在整体上多呈现极强的规律性,其中最为典型的就是数据局部性(data locality)。数据局部性包括时间局部性和空间局部性。伸展树正是基于数据的时间局部性和空间局部性原理产生的。

二 时间局部性和空间局部性的原理

时间局部性和空间局部性的原理如下。

• 刚刚被访问的元素,极有可能在不久后再次被访问。

• 刚刚被访问的元素,它的相邻节点也很有可能被访问。

树的搜索时间复杂度与树的高度相关。二叉搜索树的高度在最坏情况下为 n ,每次搜索的时间复杂度都退化为线性 O (n )。平衡二叉树(AVL树)通过动态调整平衡,使树的高度保持在O (logn ),因此单次搜索的时间复杂度为O (logn )。但是AVL树为了严格保持平衡,在调整时会做过多旋转,影响了插入和删除的性能。

伸展树的实现更为简捷,它无须时刻保持全树平衡,任意节点的左右子树高差无限制。伸展树的单次搜索也可能需要 n 次操作,但可以在任意足够长的真实操作序列中保持均摊意义上的高效率 O (logn)。伸展树可以保证 m 次连续搜索操作的复杂度为 O (m logn),而不是O (mn)。伸展树的优势在于不需要记录平衡因子、树高、子树大小等额外信息,所以适用范围更广,对 m 次连续搜索操作具有较高的效率。

考虑到局部性原理,伸展树会在每次操作后都将刚被访问的节点旋转至树根,加速后续的操作。当然,旋转前后的搜索树必须相互等价。这样,查询频率高的节点应当经常处于靠近树根的位置。旋转的巧妙之处:在不打乱数列中数据大小关系(中序遍历有序性)的情况下,所有基本操作的均摊复杂度仍为O (logn)。

三 右旋和左旋

伸展操作 Splay(x , goal) 是在保持伸展树有序性的前提下,通过一系列旋转将伸展树中的元素 x 调整到 goal 的子节点,若 goal=0,则将元素 x 旋转到树的根部。伸展操作包括右旋和左旋两种基本操作。

1 右旋

节点 x 右旋时,携带自己的左子节点向右旋转到 y 位置,y 旋转到 x 的右子树位置,x 的右子树被抛弃,此时 y 右旋后左子树正好空闲,将 x 的右子树放到 y 的左子树位置,旋转后将 x 挂接到 y 的父节点,若原来 y 是其父节点的右子节点,则旋转后 x 也是其父节点的右子节点,否则是其父节点的左子节点。旋转时修改

了3对父子关系,即 y 和 xr 、y 的父节点 tr[y ].fa 和 x 、x 和 y ,如下图中的粗线所示。

2 左旋

节点 x 左旋时会携带自己的右子节点,向左旋转到 y 的位置,y 旋转到 x 的左子树位置,x 的左子树被抛弃,此时 y 左旋后其右子树正好空闲,将 x 的左子树放到 y 的右子树位置,旋转后将 x 挂接到 y 的父节点 tr[y ].fa ,若原来 y 是其父节点的右子节点,则旋转后 x 也是其父节点的右子节点,否则是其父节点的左

子节点。

四 伸展

伸展操作并不复杂,根据情况右旋或左旋就可以了。伸展操作分为逐层伸展和双层伸展。

1 逐层伸展

将 x 旋转到目标 goal之下,若 x 的父节点不是目标,则判断:若 x 是其父节点的左子节点,则执行 x 右旋;否则执行 x 左旋,直到 x 的父节点等于目标为止。若目标为 0,则 x 为树根。

例如,在下面的伸展树中将 1 旋转到树根,逐层伸展的旋转过程如下图所示。

算法分析: 采用逐层伸展的方法,每次访问的时间复杂度在最坏情况下都为O (n),如何避免最坏情况的发生呢?一个简单有效的方法是双层伸展,即每次都向上追溯两层,判断旋转类型并进行相应的旋转。

2 双层伸展

双层伸展每次都向上追溯两层,旋转类型分为 3 种情况。

情况1:Zig/Zag

若节点 x 的父节点 y 是根节点,则只需进行一次右旋或左旋操作即可。若 x 是其父节点 y 的左子节点,则执行 x 右旋,否则执行 x 左旋。

情况2:Zig-Zig / Zag-Zag

若节点 x 的父节点 y 不是根节点,y 的父节点为 z ,且 x、y 同时是各自父节点的左子节点或右子节点,则需要进行两次右旋或两次左旋操作。

情况3:Zig-Zag / Zag-Zig

若节点 x 的父节点 y 不是根节点,y 的父节点是 z ,且在 x、y 中一个是其父节点的左子节点,一个是其父节点的右子节点,则需要进行两次旋转:右旋-左旋或两次左旋-右旋操作。

3 分析

情况 1 和情况 3 都进行了 x 的右旋或左旋,和逐层伸展的方法完全一致,情况 2 则有所不同:逐层伸展时进行了两次 x 旋转,双层伸展时先进行 y 旋转再进行 x 旋转。

例如,在下面的伸展树中将 1 旋转到树根,双层伸展的旋转过程如下图所示。

旋转之后,双层伸展比逐层伸展得到的树高度更小,基本操作的时间复杂度和树高成正比,因此双层伸展比逐层伸展效率更高。

算法分析: 双层伸展可以使树的高度接近于减半的速度压缩。Tarjan 等人已经证明,双层伸展单次操作的均摊时间为 O(logn),比逐层伸展的效率高了很多。逐层伸展简单、易懂,在数据量不大的情况下可以通过,若数据量大或特殊数据卡点,则会超时。

五 查找

与二叉搜索树的查找一样,在伸展树中查找 val,若查找成功,则将 val 旋转到根。

六 插入

与二叉搜索树的插入一样,将 val 插入伸展树的相应位置,再执行 Splay(x , 0)。初始时,x=root,若 tr[x ].val<val,则到 x 的右子树中查找,否则到 x 的左子树中查找;若 x 的子树不存在,则停止,生成新节点挂到 x 的子树上,然后将新插入的节点旋转到树根。

七 分裂

以 val 为界,将伸展树分裂为两棵伸展树 t1 和 t2 ,t1 中的所有元素都小于 val , t2 中的所有元素都大于 val 。 首先执行 Find(val),将元素 val 调整为伸展树的根节点,则 val 的左子树就是 t1 ,右子树为 t2 。删除树根,分裂为 t1 和 t2 两棵伸展树。

八 合并

将两个伸展树 t1 和 t2 合并为一个伸展树,t1 的所有元素都小于 t2 的所有元素。首先,找到伸展树 t1 中的最大元素 x ,查找最大值时会通过伸展操作将 x 调整到伸展树的根;然后,将 t2 作为树根 x 的右子树。这样就得到了新的伸展树 root。

九 删除

将元素 val 从伸展树中删除。首先在伸展树中查找 val,然后以 val 为界,将伸展树分裂为两棵伸展树 t1 和 t2 ,再将两个伸展树合并。

十 区间操作

若伸展树中节点的值为数列中每个元素的位置,则可以利用伸展树实现线段树的所有功能,还可以实现线段树无法实现的功能,例如删除区间和插入区间。

1 删除区间

删除 [l , r ] 区间的所有元素。首先找到 l-1,将其旋转到树根;然后找到 r+1,将其旋转到树根的右子节点,此时 r +1 的左子树为 [l, r ]区间,将 r+1 的左子树置空。

2 插入区间

在 pos 后插入一些元素 {a1 , a2 , …, ak }。首先将这些元素建成一棵伸展树 t1,然后找到 pos,将其旋转到树根;最后找到 pos+1,将其旋转到树根的右子节点,将 t1 挂接到 pos+1 的左子树上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/37475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode】882. 细分图中的可到达节点

题目描述 给你一个无向图&#xff08;原始图&#xff09;&#xff0c;图中有 n 个节点&#xff0c;编号从 0 到 n - 1 。你决定将图中的每条边 细分 为一条节点链&#xff0c;每条边之间的新节点数各不相同。 图用由边组成的二维数组 edges 表示&#xff0c;其中 edges[i] [ui…

ESG,TO B长期主义里的「新战役」

中国企业最好的方式是从初始阶段就植入ESG基因&#xff0c;使它逐渐从隐形变成显性基因。长期坚持此类发展导向&#xff0c;对后续发展ESG战略&#xff0c;提升ESG合规能力也将成为一种积累和准备。 作者|三七 编辑|皮爷 出品|产业家 20世纪初期&#xff0c;伦敦得到一个延…

MyBaits-Plus中@TableField和@TableId用法

目录 前言 一、TableField(value "表字段") 二、TableField(select false) 三、TableField(exist false) 四、TableId(type IdType.AUTO)补充 总结 前言 接着前两篇mybatis-plus的知识点 Mybatis-Plus知识点[MyBatisMyBatis-Plus的基础运用]_心态还需努力呀…

论文阅读: Disentangled lmage Colorization via Global Anchors

Disentangled lmage Colorization via Global Anchors发表于SIGGRAPH ASIA 2022&#xff0c;是一篇基于深度学习的图像彩色化的工作&#xff0c;简单介绍一下。之前曾分享过一篇彩色化的经典论文&#xff1a;经典论文回顾: Colorization using Optimization。 作者认为图像彩色…

【数据库】索引

MySQL索引 1、B树索引 是InnoDB引擎默认的索引 B树结构 B树是平衡树&#xff0c;即所有叶子节点都在同一层的多叉树 每个节点中key和指针交替排列&#xff0c;两个key之间的指针指向的是大于等于左边key且小于等于右边key的节点 叶子节点顺次连接&#xff0c;所以沿着B树的叶…

ADAU1860调试心得(5)ADC-DAC直通程序

硬件、驱动全部都搞好了&#xff0c;我觉得调试记录的话&#xff0c;就从最简单的开始&#xff0c;先做一个直通的例程。先把这个板子弄出声来&#xff0c;会用sigmastudio&#xff0c;会做ADAU开发的兄弟们应该很熟悉&#xff0c;同样的配方&#xff0c;同样的味道&#xff0c…

Nginx--单向链表分析

1.基本数据结构 1.1结点 struct ngx_list_part_s {void *elts;ngx_uint_t nelts;ngx_list_part_t *next; };结构成员分析 void* elts :数组元素指针 ngx_uint_t :数组里面的元素数量 ngx_list_part_t*…

英文Assignment写作引用格式怎么分析?

英文Assignment写作中我们常常使用不同作家和研究员的观点&#xff0c;论证来支持自己的想法。引用他们原文的时候我们必须使用具体引用格式。不同学校对引用格式都有不同的要求。事实上&#xff0c;有很多不同的引用格式&#xff0c;大约有超过200种引用格式。例如我们耳熟能详…

一文读懂!异常检测全攻略!从统计方法到机器学习

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; 数据分析实战系列&#xff1a;https://www.showmeai.tech/tutorials/40 &#x1f4d8; 机器学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/41 &#x1f4d8; 本文地址&#xff1a;https://showmea…

Day12--优化分类页面的效果

1.提出一个问题&#xff0c;当你点击一级分类的时候&#xff0c;在三级分类中滚动自己的进度条。切换到之后的另一级分类再看看其三级分类时不是再最顶部。 我的操作&#xff1a; 1》在cate.vue中&#xff1a; *************************************************************…

大数据必看:大厂十年架构师职业生涯实战经验总结,《大规模分布式系统架构与设计实战》

前言 这段时间一直在读一本书《大规模分布式系统架构与设计实战》&#xff0c;这是淘宝千峰老师的作品&#xff0c;是从程序员到首席架构师十多年职业生涯的实战经验总结。 这本书其实是围绕着Fourinone在讲分布式&#xff0c;并非分布式理论&#xff0c;所以只适用于想研究F…

【allegro 17.4软件操作保姆级教程五】布线前准备之过孔、差分对、布线集合添加

目录 1.1 过孔添加与设置 1.2 添加差分对 1.3 添加布线集合 1.1 过孔添加与设置 布线换层时需要由过孔贯穿&#xff0c;而软件本身是没有过孔可以直接调用的&#xff0c;所以需要手动添加和设置。一般我们使用的都是通孔&#xff0c;盲孔和埋孔成本高&#xff0c;一般不使用。…

PG::Photography

nmap -Pn -p- -T4 --min-rate1000 192.168.171.76 nmap -Pn -p 22,80,139,445,8000 -sCV 192.168.171.76 查看8000端口的内容 CMS的关键字“Built with Koken” 存在的漏洞需要认证 https://www.exploit-db.com/exploits/48706 在端口枚举时&#xff0c;该靶机有smb服务&am…

MyBatis-Plus之DML编程控制

1. id生成策略控制 前面我们在新增的时候留了一个问题&#xff0c;就是新增成功后&#xff0c;主键ID是一个很长串的内容&#xff0c;我们更想要的是按照数据库表字段进行自增长&#xff0c;在解决这个问题之前&#xff0c;我们先来分析下ID该如何选择&#xff1a; 不同的表应…

vscode一键生成佛祖保佑永无bug

工欲善其事&#xff0c;必先利其器 今天给大家分享一个vscode注释插件-koroFileHeader&#xff0c;可以快速给我们的文件和函数添加注释&#xff0c;快来看看吧 安装 打开vscode拓展&#xff0c;搜索“koroFileHeader”&#xff0c;安装&#xff0c;重新启动一下 使用 快捷键 生…

【配置nacos】使用application.yml配置文件来配置spring-cloud-starter-alibaba-nacos-config

1.首先修改pom.xml文件&#xff0c;引入spring-cloud-starter-alibaba-nacos-config依赖 <!--Nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><…

Java#26(常见算法: 排序算法)

目录 一.冒泡排序 相邻元素之间两两比较,大的放右边,小的放左边 二.选择排序 从0索引开始,拿着每一个索引上的元素和后面的元素依次标胶,小的放在前面,大的放在后面 三.插入排序 假如0到n索引的数据遵循从小到大排序,就可以将0-n看做有序的,则n1到最大索引都是无序的 四…

【日常系列】LeetCode《19·BFS 和 DFS》

数据规模->时间复杂度 <10^4 &#x1f62e;(n^2) <10^7:o(nlogn) <10^8:o(n) 10^8<:o(logn),o(1) 内容 lc 589 &#xff1a;N 叉树的前序遍历 https://leetcode.cn/problems/n-ary-tree-preorder-traversal/ 提示&#xff1a; 节点总数在范围 [0, 104]内 0 &l…

最简单的git图解(git rebase)

今天我们来讲解下git rebase命令&#xff0c;以及git rebase命令与git merge命令的区别。 git rebase图解&#xff1a; 假设我们目前有master、demo两个分支&#xff0c;而且demo分支上从master分支上切出来的&#xff1a; 从上图中可以看到&#xff0c;我们从C2提交点切出来了…

图像边缘检测与图像分割常用算法研究分析-含Matlab代码

⭕⭕ 目 录 ⭕⭕✳️ 引言✳️ 一、经典边缘检测算子✳️ 1.1 Roberts 算子与实验验证✳️ 1.2 Sobel 算子原理与实验验证✳️ 1.3 Prewitt 算子与实验验证✳️ 1.4 Log 算子与实验验证✳️ 1.5 Canny 算子与实验验证✳️ 二、图像分割原理及其实验验证✳️ 2.1 基于阈值处理的…