C/C++ 进阶(5)二叉平衡搜索树(AVL树)

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

目录

一、概念

二、平衡因子

三、操作

插入

旋转

左单旋

右单旋

左右双旋

右左双旋


一、概念

二叉平衡搜索树又称AVL树,是一种特殊的二叉搜索树。一般的二叉搜索树在遇到数据有序时,查找的效率比较的低。

而二叉平衡搜索树,为了防止有这种极端的情况出现,其保证了任一节点的左右子树的高度差不超过1,通过控制高度,使查找的次数降低。 

二、平衡因子

二叉平衡搜索树,在对节点的结构进行定义的时候多添加了一个平衡因子的变量(bf),用来判断树是否是平衡的

平衡因子 = 右子树的高度 - 左子树的高度

平衡因子的取值为 :0、+1、-1、+2、-2

当平衡因子为+2、-2的时候,代表了这棵树需要进行调整。

三、操作

插入

插入的步骤就是这些。

为什么调节完,平衡因子为1、-1的时候要向上进行调整? 

如果调节完,平衡因子为1、-1,则在没有调整的时候,平衡因子为0。新增了一个结点之后,高度发生了变化。以当前节点为根节点的子树的高度发生了变化,则以当前节点为其中的一个节点的子树的高度也同样发生了变化,所以需要进行调整。

旋转

对于要通过旋转进行调节平衡因子的情况不细分的话,有4种:左单旋、右单旋、左右双旋、右左双旋。

注意:在进行旋转的时候,对于每个节点的指针变化,要特别的细心。

节点中有三个指针,一个指向左孩子、一个指向右孩子、另外一个指向双亲。

旋转点:进行旋转的一个基准点。就比如左单旋的话,parent就是旋转点。

左单旋

左单旋变换:subrl 变成 parent 的右子树,parent 成为 subr 的左子树。

直接看图变换是不难,但是写代码就会有很多的坑(指针的变换)。

// 左单旋
// 参数是图中的parent,也称为旋转点
void RotateL(node* parent)
{node* subr = parent->right;node* subrl = subr->left;// subrl 成为 parent 的右子树 parent->right = subrl;if (subrl)subrl->parent = parent;subr->left = parent;node* pparent = parent->parent;parent->parent = subr;if (_root != parent){if (pparent->left == parent){pparent->left = subr;}else {pparent->right = subr;}subr->parent = pparent;}else{_root = subr;subr->parent = nullptr;}parent->bf = subr->bf = 0;
}

右单旋

如图是右单旋的情况。

右单旋的变换:sublr 变成 parent 的左子树,将parent 变成 subl 的右子树。

直接看图变换是不难,但是写代码就会有很多的坑(指针的变换)。

// 右单旋
// parent 为旋转点
void RotateR(node* parent)
{node* subl = parent->left;node* sublr = subl->right;// sublr成为parent的左子树parent->left = sublr;// 如果sublr是空的话,不需要更新它的双亲结点,因为空指针不能进行解引用if (sublr)sublr->parent = parent;// parent成为subl的右子树subl->right = parent;// 记录一下这个子树的根节点的双亲结点node* pparent = parent->parent;// 更新parent的双亲节点parent->parent = subl;// 判断该子树的根节点是不是整个子树的根节点// 不是的话,也需要更新该子树的根节点的双亲结点if (_root != parent){if (pparent->left == parent){pparent->left = subl;}else {pparent->right = subl;}subl->parent = pparent;}else{_root = subl;subl->parent = nullptr;}// 更新平衡因子parent->bf = subl->bf = 0;
}

左右双旋

左右双旋的变换:先以 subl 为旋转点进行左单旋,然后再以 parent 为旋转点进行右单旋。

注意:1、指针的变换 2、注意新的节点插入在 b 子树的左子树和右子树的时候,平衡因子的变化。

 

// 左右双旋
// 传参传的节点还是parent
void RotateLR(node* parent)
{node* psubl = parent->left;node* psublr = psubl->right;// 记录之前的 sublr 节点的平衡因子int bf = psublr->bf;// 先以 subl 为旋转点进行左单旋RotateL(parent->left);// 然后再以 parent 为旋转点进行右单旋RotateR(parent);// 在完成旋转调整平衡后,在对该子树的平衡因子进行变换// 至于为什么平衡因子等于这些值,可以去看看我画的图然后进行对比// 还是比较清楚的if (-1 == bf){psubl->bf = psublr->bf = 0;parent->bf = 1;}else if (1 == bf){parent->bf = psublr->bf = 0;psubl->bf = -1;	}else if (0 == bf) // 如果在旋转之前的平衡因子就是为0,则调整完之后的平衡因子都是0{parent->bf = psubl->bf = psublr->bf = 0;}else // 这种情况一般是没有的,如果有,则是你写的AVL树是有错误的{assert(false);}
}

 

右左双旋

右左双旋的变换:先以 subr 为旋转点进行右单旋,然后再以 parent 为旋转点进行左单旋。

注意:1、指针的变换 2、注意新的节点插入在 c 子树的左子树和右子树的时候,平衡因子的变化。

 

// 右左双旋
void RotateRL(node* parent)
{node* psubr = parent->right;node* psubrl = parent->left;int bf = psubrl->bf;// 先以subr为旋转点进行右单旋RotateR(parent->right);// 再以parent为旋转点进行左单旋RotateL(parent);// 更新平衡因子if (1 == bf){psubr->bf = psubrl->bf = 0;parent->bf = -1;}else if (-1 == bf){parent->bf = psubrl->bf = 0;psubr->bf = 1;}else if (0 == bf){parent->bf = psubr->bf = psubrl->bf = 0;}else {assert(false);}
}

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

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

相关文章

SOLIDWORKS修改零件时出现错误怎么办?

我们在使用SOLIDWOKRS进行零件建模过程中往往避免不了修改,但在修改后又常常会出现零件报错的情况,设计树中会出现一堆的错误和警告,我们如何快速处理这些问题呢? 我们都知道SOLIDWOKRS零件通常包含两大类的对象,分别…

Docker 入门版

目录 1. 关于Docker 2. Dockr run命令中常见参数解读 3. Docker常见命令 4. Docker 数据卷 5. Docker本地目录挂载 6. 自定义镜像 Dockerfile 语法 自定义镜像模板 Demo 7. Docker网络 1. 关于Docker 在docker里面下载东西,就是相当于绿色面安装板&#x…

python之生成器表达式

背景 生成器表达式,整个表达式都是另一个函数的唯一入参,则不需要带括号;若他只是其中一个参数,则需要圆括号包裹。 演示

响应式流和reactor框架进阶

响应式流和reactor框架进阶 响应式流创建、转换、处理 本文档主要介绍在响应式编程中如何从流中获取数据并处理。 前提条件 假设您已经能掌握Java基础、Maven使用、Lamda表达式、响应式编程等基础。 如何获取流中数据 🌏 说明 1、不要试图从流中获取数据出来&a…

MMUNet:形态学特征增强网络在结肠癌病理图像分割中的应用

MMUNet: Morphological feature enhancement network for colon cancer segmentation in pathological images. 发表在:Biomedical Signal Processing and Control2024--影响因子:3.137 南华大学的论文 论文地址:main.pdf (sciencedirecta…

地理信息科学中的大数据挑战

在信息化爆炸的时代,地理信息科学(GIScience)正经历着前所未有的变革,其中,地理空间大数据的涌现为科学研究与应用带来了前所未有的机遇与挑战。作为地理信息与遥感领域的探索者,本文旨在深入剖析地理空间大…

找不到steam_api64.dll,无法继续执行的原因及解决方法

电脑已经成为我们生活中不可或缺的一部分。然而,在使用电脑的过程中,我们经常会遇到一些常见的问题,其中之一就是找不到某个特定的动态链接库文件,比如steamapi64.dll。这个问题可能会导致某些应用程序无法正常运行,给…

音视频开发—音频相关概念:数模转换、PCM数据与WAV文件详解

文章目录 前言1.模拟数字转换(ADC)1.1ADC的关键步骤: 2.数字模拟转换(DAC)2.1DAC 的基本流程包括: 3.PCM数据3.1PCM 数据的关键要素包括: 4.WAV文件4.1 WAV的构成4.2WAV文件的标准块结构4.3WAV的…

kettle从入门到精通 第六十五课 ETL之kettle 执行动态SQL语句,轻松实现全量增量数据同步

本次课程的逻辑是同步t1表数据到t2表,t1和t2表的表机构相同,都有id,name,createtime三个字段。 CREATE TABLE t1 (id bigint NOT NULL AUTO_INCREMENT,name varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,cr…

View->Bitmap缩放到自定义ViewGroup的任意区域(Matrix方式绘制Bitmap)

Bitmap缩放和平移 加载一张Bitmap可能为宽高相同的正方形,也可能为宽高不同的矩形缩放方向可以为中心缩放,左上角缩放,右上角缩放,左下角缩放,右下角缩放Bitmap中心缩放,包含了缩放和平移两个操作&#xf…

数据整理操作及众所周知【数据分析】

各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…

Opencv 色彩空间

一 核心知识 色彩空间变换; 像素访问; 矩阵的、-、*、、; 基本图形的绘制 二 颜色空间 RGB:人眼的色彩空间; OpenCV默认使用BGR; HSV/HSB/HSL; YUV(视频); 1 RGB 2 BGR 图像的多种属性 1 访问图像(Ma…

Pytorch 笔记

执行下面这段代码后,为什么返回的是 2 ? vector torch.tensor([7, 7]) vector.shape为什么返回的是 torch.Size([2])? 当你创建一个PyTorch张量时,它会记住张量中元素的数量和每个维度的大小。在你的代码中,torch.t…

Redis 线程模型

Redis 线程模型 背景简介Redis 单线程客户端发起 Redis 请求命令的工作原理单线程面临的挑战及问题 Redis 多线程Redis v4.0 多线程命令Redis v6.0 多线程网络模型 总结 背景 随着年龄的增长,很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来,技术…

LangChain学习之 Question And Answer的操作

1. 学习背景 在LangChain for LLM应用程序开发中课程中,学习了LangChain框架扩展应用程序开发中语言模型的用例和功能的基本技能,遂做整理为后面的应用做准备。视频地址:基于LangChain的大语言模型应用开发构建和评估。 2. Q&A的作用 …

了解VS安全编译选项GS

缓冲区溢出攻击的基本原理就是溢出时覆盖了函数返回地址,之后就会去执行攻击者自己的函数; 针对缓冲区溢出时覆盖函数返回地址这一特征,微软在编译程序时使用了安全编译选项-GS; 目前版本的Visual Studio中默认启用了这个编译选项…

Java-----String类

1.String类的重要性 经过了C语言的学习,我们认识了字符串,但在C语言中,我们表示字符串进行操作的话需要通过字符指针或者字符数组,可以使用标准库中提供的一系列方法对字符串的内容进行操作,但这种表达和操作数据的方…

Go语言交叉编译

Golang 支持交叉编译, 在一个平台上生成然后再另外一个平台去执行。 以下面代码为例 build ├── main.go ├── go.mod main.go内容 package mainimport "fmt"func main() {fmt.Println("hello world") }windows系统上操作 1.cmd窗口编译…

【OCPP】ocpp1.6协议第4.2章节BootNotification的介绍及翻译

目录 4.2、BootNotification-概述 Boot Notification 消息 BootNotification 请求消息 BootNotification 响应消息 使用场景 触发 BootNotification 的条件 实现示例 构建请求消息 发送请求并处理响应 小结 4.2、BootNotification-原文译文 4.2.1、被中央系统接受之…

ios v品会 api-sign算法

vip品会 api-sign算法还原 ios入门案例 视频系列 IOS逆向合集-前言哔哩哔哩bilibili 一、ios难度与安卓对比 这里直接复制 杨如画大佬的文章的内容: ios难度与安卓对比 很多人说ios逆向比安卓简单,有以下几个原因 1 首先就是闭源,安卓开源…