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.rhkb.cn/news/208261.html

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

相关文章

中国湖泊面积-水位长时序数据产品(2000-2020)

今天我们分享中国湖泊面积-水位长时序数据产品&#xff08;2000-2020&#xff09; 该数据集包含中国典型湖泊2000-2020年最大水体面积、多年平均面积、水位变化速率及空间分布矢量。 数据溯源信息 「数据来源描述」Landsat、HJ、ZY、Jason、ENVISAT、Cryosat、ICESat和HY 「数…

hls实现播放m3u8视频将视频流进行切片 HLS.js简介

github官网GitHub - video-dev/hls.js: HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.HLS.js is a JavaScript library that plays HLS in browsers with support for MSE. - GitHub - video-dev/hls.js: HLS.js is a JavaScript library …

无桌面版docker在Ubuntu系统上安装

目录 注意 系统要求 卸载旧版本 安装 使用apt存储库安装 1. 设置 Docker 的apt存储库。 2. 安装Docker软件包 3. 通过运行镜像来验证Docker Engine安装是否成功 hello-world。 从包中安装 1. 进入 https://download.docker.com/linux/ubuntu/dists/。 2. 在列表中选择…

ubuntu22.04新机使用(换源,下载软件,安装显卡驱动,锁屏长亮)

换源 国内有很多Ubuntu的镜像源&#xff0c;包括阿里的、网易的&#xff0c;还有很多教育网的源&#xff0c;比如&#xff1a;清华源、中科大源。推荐使用中科大源&#xff0c;快得很。 /etc/apt/sources.list编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前…

KEPserver和S7-200SMART PLC通信配置

KEPserver和S7-1200PLC通信配置,请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/134683670https://rxxw-control.blog.csdn.net/article/details/134683670 1、OPC通信应用 2、选择Siemens驱动 3、添加S7-200设备

k8s部署jenkins

1.先决条件 1.因为国内的容器镜像加速器无法实时更新docker hub上的镜像资源.所以可以自己进行jenkins的容器镜像创建,. 2.这里用到了storageClass k8s的动态制备.详情参考: k8s-StoargClass的使用-基于nfs-CSDN博客 3.安装docker服务.(用于构建docker image) 2.构建jenki…

C++学习之路(十六)C++ 用Qt5实现一个工具箱(为屏幕颜色提取功能增加一个点击复制的功能)- 示例代码拆分讲解

上篇文章&#xff0c;我们用 Qt5 实现了在小工具箱中添加了《颜色代码转换和屏幕颜色提取功能》功能。今天我们把屏幕颜色提取的功能再扩展一下&#xff0c;让它可以点击复制吧。下面我们就来看看如何来规划开发这样的小功能并且添加到我们的工具箱中吧。 老规矩&#xff0c;先…

AntDB数据库:从海量数据处理,到5G计费商用核心

AntDB数据库自2008年研发面世以来&#xff0c;首先被应用于运营商的核心系统&#xff0c;满足运营商海量数据处理的需求。随着数字科技的不断发展&#xff0c;AntDB也在不断地更新迭代&#xff0c;逐渐地为更多行业与客户提供更全面的服务。5G时代来临&#xff0c;AntDB抓住发展…

Linux 磁盘分区处理

最近实施过程中遇到客户提供给我们的服务器操作系统和Docke容器环境都已经安装完成&#xff0c;但磁盘的分区没有进行整理好。磁盘总共270G&#xff0c;系统安装分配了60G&#xff0c;剩余未创建分配需要处理。由于分区情况每家不一样&#xff0c;但大致流程都是相同的&#xf…

uniapp地图基本使用及解决添加markers不生效问题?

uniapp地图使用 App端 通过 nvue 页面实现地图 文章目录 uniapp地图使用效果图templatejs添加 marker使用地图查看位置移到到当前位置 效果图 template <template><view class"mapWrap"><!-- #ifdef APP-NVUE --><map class"map-containe…

一篇带你串通数据结构

文章目录 导论数据结构的定义数据结构在计算机科学中的重要性为什么学习数据结构很重要 1、基本概念1.1、数据、数据元素和数据项的概念1.2、数据对象与数据结构的关系1.3、逻辑结构与物理结构 2、线性结构2.1、数组2.2、链表2.3、栈2.4、队列 3、非线性结构3.1、树3.2、图 4、…

P1 什么是链表 C语言简单易懂

目录 前言 01 什么是链表 02 数组的特点 03 数组的缺点 3.1 删除数组其中一个元素 3.2 数组增加某个节点 04 链表 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《 C 》✨✨✨ &#x1f525; 推荐专栏2: 《 Linux C应用编程&#xff08;概念…

【1】基于多设计模式下的同步异步日志系统

1. 项目介绍 本项⽬主要实现⼀个⽇志系统&#xff0c; 其主要⽀持以下功能: • ⽀持多级别⽇志消息 • ⽀持同步⽇志和异步⽇志 • ⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中 • ⽀持多线程程序并发写⽇志 • ⽀持扩展不同的⽇志落地⽬标地 2. 开发环境 • CentOS 7 • vs…

存储虚拟化的写入过程

存储虚拟化的场景下&#xff0c;整个写入的过程。 在虚拟机里面&#xff0c;应用层调用 write 系统调用写入文件。write 系统调用进入虚拟机里面的内核&#xff0c;经过 VFS&#xff0c;通用块设备层&#xff0c;I/O 调度层&#xff0c;到达块设备驱动。虚拟机里面的块设备驱动…

K7系列FPGA多重启动(Multiboot)

Xilinx 家的 FPGA 支持多重启动功能&#xff08;Multiboot&#xff09;&#xff0c;即可以从多个 bin 文件中进行选择性加载&#xff0c;从而实现对系统的动态更新&#xff0c;或系统功能的动态调整。 这一过程可以通过嵌入在 bit 文件里的 IPROG 命令实现上电后的自动加载。而…

自定义类型-结构体,联合体和枚举-C语言

引言 能看到结构体&#xff0c;说明C语言想必学习的时间也不少了&#xff0c;在之前肯定也学习过基本数据类型&#xff0c;包括整型int&#xff0c;浮点型float等等。可是在日常生活中&#xff0c;想要描述一个事物并没有那么简单。比如&#xff0c;你要描述一本书&#xff0c…

Linux常见指令大全及周边知识:让你的命令行变得更加强大

文章目录 目录 文章目录 前言 一&#xff0c;Linux操作系统是啥&#xff1f; 二&#xff0c;Linux操作系统具有以下特点 三&#xff0c;指令的学习 1&#xff0c;指令是什么&#xff1f; 2&#xff0c;ls 指令及其常用的衍生指令&#xff1a; 周边知识&#xff1a; ls…

解决Wireshark分析RTMP抓包时Unknown问题

使用Wireshark抓包时&#xff0c;经常出现很多Unknown包&#xff0c;但实际上的字节流实际是正常的。 其实&#xff0c;RTMPT设置里有一个最大包大小的设置&#xff0c;默认是32768&#xff0c;而且默认RTMPT协议配置了从多个TCP流中重组RTMPT的功能(应当是考虑基于HTTP的传输…

RPC和HTTP的区别

目录 1、RPC是什么 1.1 概念 1.2 RPC的组成部分 1.3 常见的 RPC 技术和框架 1.4 RPC的工作流程 2、HTTP是什么 2.1 概念 2.2 HTTP的消息格式 2.3 HTTP响应状态码有哪些 3、⭐RPC和HTTP的区别 小结 1、RPC是什么 1.1 概念 RPC&#xff08;Remote Procedure Call&am…

MySQL字符函数

在数据库中&#xff0c;字符函数是一组用于处理字符串的函数。这些函数可以帮助我们执行各种操作&#xff0c;如连接、比较、替换等。本文将介绍一些常用的MySQL字符函数&#xff0c;并演示如何在查询中使用它们。 1.concat() 函数 CONCAT() 函数用于连接两个或多个字符串。它…