12.1平衡树(splay),旋转操作及代码

平衡树

变量定义

tot表示结点数量,rt表示根的编号

v[i]表示结点i的权值

fa[i]表示结点i的父亲节点

chi[i][2]表示结点i的左右孩子

cnt[i]表示结点i的权值存在数量,如1123,v[3]=1,则cnt[3]=2;就是说i=3的三号结点的权值为1,那么三号结点的权值存在数量为2,即有两个1存在于数列当中,也就是说自变量是结点编号,因变量是结点的权值以及对应权值出现的次数

sz[i]表示结点i的子树中权值数量。sz[i]=sz[chi[i][0]]+sz[chi[i][1]]+cnt[i]

就是说i号结点存在的value的值的数量,chi[i][0]与chi[i][1]返回的是i号结点对应的两个孩子的编号,加起来就是左边的数量和右边的数量与根节点的数量和

操作

查询x的前驱:如果x有左子树,那么前驱是左子树里最靠右的结点;如果x没有左子树但有父亲结点,那么前驱是它左子树内最靠右的结点。

查询x的排名:如果x小于当前权值,则向左子树。答案加上左子树大小,如果x等于当前权值,将答案+1并返回;否则加上当前节点的cnt并向右子树

查询排名为k的数值:如果k小于左子树的大小,则向左子树

将k减去左子树大小,如果k<=0,则返回当前权值,否则向右子树

旋转

旋转操作的输入是原根节点,输出是新根结点

旋转的操作是对根节点而言的,就是说左旋是右孩子向左旋转上来;右旋是左孩子旋转上来

左旋就是右孩子成为根节点,然后原根节点成为新根结点的左孩子,新根结点的左孩子成为原根节点的最右侧孩子;右旋是左孩子成为新根节点,然后原根节点成为新根结点的右孩子,新根结点的右孩子成为

就右旋而言,要变的就两步,一步是让左孩子成为新根(也意味着左孩子失去原来的右孩子,原根节点失去原来的左孩子),另一步是让左孩子(新根)失去的右孩子接到原根(新根的右子树)的左侧

注意,由于原根失去左孩子(失去的左孩子成为了新根),所以原根在成为新根的右孩子节点时,是一定没有左孩子的,所以不用担心接不上以及接的位置,原根的左孩子的右孩子是一定可以接到原根的左孩子上的

原根A,原根左孩子B,原根左孩子的右孩子C,

用一个指针,定义为A的左孩子(即B),即表示右旋后的新的新根结点B。然后让A的左孩子为新根结点B的右孩子C(此时B还没发生改变),之后A就发生了变化,即左孩子不再是B而是C,然后再用新根指针,使B的右孩子为A

就是说在这一过程中,用了两个指针,一个指针为原根结点(输入),一个指针为新根结点(输出)

class TreeNode:def __init__(self, val):self.val = valself.left = Noneself.right = Nonedef left_rotation(node):new_root = node.rightnode.right = new_root.leftnew_root.left = nodereturn new_rootdef right_rotation(node):new_root = node.leftnode.left = new_root.rightnew_root.right = nodereturn new_root

左旋:

旋转操作是平衡二叉树中常用的操作,用于调整树的结构以保持平衡性。平衡二叉树的旋转操作包括左旋、右旋、左右旋和右左旋。

1. 左旋(Left Rotation):对于一个节点,将其右子节点变为新的根节点,原根节点成为新根节点的左子节点,原右子节点的左子节点成为原根节点的右子节点。这个操作用于解决在插入或删除某个节点导致右子树过高的情况。

2. 右旋(Right Rotation):对于一个节点,将其左子节点变为新的根节点原根节点成为新根节点的右子节点,原左子节点的右子节点成为原根节点的左子节点。这个操作用于解决在插入或删除某个节点导致左子树过高的情况。

3. 左右旋(Left-Right Rotation):先对节点的左子节点进行左旋,然后再对节点自身进行右旋。这个操作用于解决在插入或删除某个节点导致左子树过高,且其左子节点的右子树过高的情况。

4. 右左旋(Right-Left Rotation):先对节点的右子节点进行右旋,然后再对节点自身进行左旋。这个操作用于解决在插入或删除某个节点导致右子树过高,且其右子节点的左子树过高的情况。

通过这些旋转操作,可以调整树的结构并保持树的平衡性。旋转操作的实质是通过节点之间的连接关系进行调整,从而改变树的形态。在实际应用中,旋转操作通常会涉及到节点的左右子树的高度计算、节点指针的重连等步骤。

需要注意的是,旋转操作只能保持局部的平衡性,有时可能需要多次旋转来达到整体的平衡。另外,旋转操作可能会改变树中节点的相对顺序,因此在进行旋转操作时需要注意维护节点的排序和二叉搜索树的性质。

struct Node
{int ch[2];int val;int ff;
}t[MAX];

ch是左右孩子。ff是记录这个结点的父节点 

inline void rotate(int x)
{int y=t[x].ff;int z=t[y].ff;int k=(x==t[y].ch[1]);t[z].ch[y==t[z].ch[1]]=x;t[x].ff=z;t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;t[x].ch[k^1]=y;t[y].ff=x;
}

 输入是x,表示要旋转的结点的编号。通过y记录x的父节点,就是说y是x的父节点;z是y的父节点,是x的爷爷结点

k是表示结点x是其父结点的什么孩子。t[y].ch[1]返回的是y号结点的右孩子编号。如果是右孩子,则判断出来是1.不然则判断出来是0,就是说是左孩子就返回0,是右孩子就返回1

对于旋转的操作,就是利用了两个指针,借助了爷爷结点,即把x接到了爷爷结点上,然后就是确定接到爷爷结点的哪个孩子结点上。

具体步骤是先让爷爷节点的孩子结点设置为x,这时会断掉z与y的联系,z与x联系上;

然后让x的父节点设置为z,这时会断掉x与y的联系,x与z联系上。此时,y的孩子结点上记录的依然是x

然后让y的孩子结点变为x的孩子结点,让x的孩子结点的父节点变为y结点

最后让x的孩子结点设置为y,把y的父节点设置为x

设x为y的k孩子(k为0时为左孩子,k为1时为右孩子),则需要进行相反的旋转操作,即k^1(与1异或;如果k为0,x为左孩子,则进行右旋操作,x变为根节点;如果k为1,则进行左旋操作)

1把x设置为新根结点

    t[z].ch[y==t[z].ch[1]]=x;t[x].ff=z;

z的作用就是接口,省去了最后返回新根结点的过程,就是让z的相应孩子结点位置变为x,即所谓新根结点。 

2.把原根结点的k孩子设为新根结点的k^1孩子

 t[y].ch[k]=t[x].ch[k^1];
    t[t[x].ch[k^1]].ff=y;

3.让新根结点的孩子设为原根节点

  t[x].ch[k^1]=y;
    t[y].ff=x;
2与3不能反转,因为如果先3的话,新根结点的原孩子就会丢失,就会导致在2的时候接不上原来的孩子,导致丢失。而如果先2的话,会使原根结点的孩子结点丢失,但是其相应位置上孩子就是x,x已经成为新根结点,所以无所谓.具体就是t[x].ch[k^1]


 

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

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

相关文章

树和二叉树的基本概念和堆的实现

树的概念及结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 1.有一个特殊的结点&#…

04-配置远程仓库的SSH免密登陆

配置SSH免密登录 配置步骤 创建好的远程仓库也可以使用SSH的方式进行访问,但如果没有配置公钥会有警告 第一步: 删除用户家目录下的.ssh目录,如果没有该目录或者该目录下已经有密钥了就不用执行该操作 #进入当前用户的家目录,删除.ssh 目录 LayneLAPTOP-Layne MINGW64 ~ $ r…

python datetime 获取特定一天的后一天或者后几天

这里写自定义目录标题 1 获取特定天的时间对象 具体时间格式参考&#xff1a;Python time strptime()和strftime()-CSDN博客 import datetimetimer datetime.datetime.strptime(date, "%Y-%m-%d")2 获取下一天或者【下x天】的数据并进行格式转换 # 下一天数据 ne…

基于SpringBoot+Vue的前后端分离的房屋租赁系统2

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 开发过程中&#xff0…

uniApp打包的手机app如果用户没开启通知权限、引导用户开启

封装一个setPermissions.js文件 /*** 如果用户没开启通知权限、引导用户开启 */ export function setPermissions() {// #ifdef APP-PLUS if (plus.os.name Android) {var main plus.android.runtimeMainActivity();var pkName main.getPackageName();var uid main.getApp…

基于WebSocket实现客户聊天室

目录 一、实现聊天室原理 二、聊天室前端代码 三、聊天室后端代码&#xff08;重点&#xff09; 四、聊天室实现效果展示 一、实现聊天室原理 1.1 介绍websocket协议 websocket是一种通信协议&#xff0c;再通过websocket实现弹幕聊天室时候&#xff0c;实现原理是客户端首…

【动态规划】LeetCode-931.下降路径最小和

&#x1f388;算法那些事专栏说明&#xff1a;这是一个记录刷题日常的专栏&#xff0c;每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目&#xff0c;在这立下Flag&#x1f6a9; &#x1f3e0;个人主页&#xff1a;Jammingpro &#x1f4d5;专栏链接&…

服务器基础知识

服务器被誉为互联网之魂。我第一次见到服务器是在学校图书馆&#xff0c;是一种机架式服务器&#xff0c;第二次见到服务器是在公司机房。本期文章是对服务器进行大盘点和梳理&#xff0c;会介绍我拆装服务器过程&#xff0c;从中的学习感悟。 图片来自 Pexels 01 服务器 服务…

VSCode 开发C/C++实用插件分享——codegeex

VSCode 开发C/C实用插件分享——codegeex 一、codegeex 一、codegeex CodeGeeX 智能编程助手是一款编程插件&#xff0c;CodeGeeX支持多种主流IDE&#xff0c;如VS Code、IntelliJ IDEA、PyCharm、Vim等&#xff0c;同时&#xff0c;支持Python、Java、C/C、JavaScript、Go等多…

图片点击放大

在列表中添加插槽 <template slot-scope"scope">&#xff0c;获取当前点击的数据 在图片中添加点击事件的方法&#xff0c;用来弹出窗口 <vxe-columnfield"icon"title"等级图标"><template slot-scope"scope"><…

PyLMKit(3):基于角色扮演的应用案例

角色扮演应用案例RolePlay 0.项目信息 日期&#xff1a; 2023-12-2作者&#xff1a;小知课题: 通过设置角色模板并结合在线搜索、记忆和知识库功能&#xff0c;实现典型的对话应用功能。这个功能是大模型应用的基础功能&#xff0c;在后续其它RAG等功能中都会用到这个功能。功…

使用MD5当做文件的唯一标识,这样安全么?

使用MD5作为文件唯一标识符可靠么&#xff1f; 文章目录 使用MD5作为文件唯一标识符可靠么&#xff1f;什么是MD5&#xff1f;MD5的用途MD5作为文件唯一标识的优劣优势劣势 使用MD5作为文件唯一标识的建议其他文件标识算法结束语 什么是MD5&#xff1f; MD5&#xff08;Messag…

postman接口测试教程与实例分享

postman 的界面图 各个功能区的使用如下&#xff1a; 快捷区&#xff1a; 快捷区提供常用的操作入口&#xff0c;包括运行收藏夹的一组测试数据&#xff0c;导入别人共享的收藏夹测试数据&#xff08;Import from file, Import from folder, Import from link等&#xff09;&…

zookeeper心跳检测 (实操课程)

本系列是zookeeper相关的实操课程&#xff0c;课程测试环环相扣&#xff0c;请按照顺序阅读来学习和测试zookeeper。 阅读本文之前&#xff0c;请先阅读----​​​​​​zookeeper 单机伪集群搭建简单记录&#xff08;实操课程系列&#xff09;zookeeper 客户端常用命令简单记录…

kubernetes中YAML介绍;API资源对象Pod;Pod原理和生命周期;Pod资源限制

YAML介绍&#xff1b;API资源对象Pod&#xff1b;Pod原理和生命周期&#xff1b;Pod资源限制 1&#xff09;认识YAML 官网&#xff08;https://yaml.org/&#xff09; YAML 语言创建于 2001 年&#xff0c;比 XML 晚了三年。YAML虽然在名字上模仿了XML&#xff0c;但实质上与…

【【FPGA 之 MicroBlaze 自定义IP核 之 呼吸灯实验】】

FPGA 之 MicroBlaze 自定义IP核 之 呼吸灯实验 通过创建和封装 IP 向导的方式来自定义 IP 核&#xff0c;支持将当前工程、工程中的模块或者指定文件目录封装成 IP 核&#xff0c;当然也可以创建一个带有 AXI4 接口的 IP 核&#xff0c;用于 MicroBlaze 软核处理器和可编程逻辑…

Day59权限提升-win溢出漏洞ATSCps提权

针对Windows系统个人主流操作系统是win7/8/10等等&#xff0c;针对服务器就win2003和2008比较多&#xff0c; 明确权限提升问题&#xff0c;web和本地&#xff1a; 举个例子&#xff0c;现在获得了一个网站权限&#xff0c;这个权限只可以对网站自身的东西进行操作&#xff0…

Python字典类型

目录 目标 版本 官方文档 简介 实战 创建 循环 常用方法 目标 掌握字典类型的使用方法&#xff0c;包括&#xff1a;创建、循环、常用方法等操作。 版本 Python 3.12.0 官方文档 Mapping Types — dicthttps://docs.python.org/3/library/stdtypes.html#mapping-type…

Halcon参考手册目标检测和实例分割知识总结

1.1 目标检测原理介 目标检测&#xff1a;我们希望找到图像中的不同实例并将它们分配给某一个类别。实例可以部分重叠&#xff0c;但仍然可以区分为不同的实例。如图(1)所示&#xff0c;在输入图像中找到三个实例并将其分配给某一个类别。 图(1)目标检测示例 实例分割是目标检…

敌方移动发射[java坦克大战]

1.首先要确保判断如果敌人坦克存活并且敌人子弹集合等于0了&#xff0c;就根据坦克方向创建一颗子弹&#xff0c;放入到shots集合&#xff0c;并启动。(逻辑&#xff1a;发射子弹后&#xff0c;敌人坦克向前移动一段距离后转向&#xff0c;敌人坦克仍然存活并且刚发射的子弹消亡…