数据结构与算法_AVL平衡二叉树_四种旋转,插入和删除

news/2024/5/2 9:33:37/文章来源:https://blog.csdn.net/weixin_43916755/article/details/128070555

1 AVL平衡二叉树的概念

平衡二叉树在BST树基础上加了平衡操作。
BST树特点 :在BST树的基础上,引入了节点“平衡”的概念,任意一个节点的左右子树高度差不超过 1 ,为了维持节点的平衡,引入了四种旋转操作,如下:
1.左孩子左子树太高,做右旋转操作
2.右孩子的右子树太高,做左旋转操作
3.左孩子的右子树太高,做左-右旋转操作(也叫左平衡操作)
4.右孩子的左子树太高,做右-左旋转操作(也叫右平衡操作)

AVL树:记忆的时候,与BST树的插入删除联系起来。
下面分别记录AVL的四种失衡操作,并举例说明。

2 AVL的四种旋转操作

2.1 右旋转

右旋转调整。如下图所示,40左子树高度为2,右子树高度为0 ,这种情况称为左失衡,需要进行右旋转。
在这里插入图片描述

2.2 左旋转

左旋转调整。当节点的右子树高度大于节点的左孩子高度时候,如下图情况,需要做左旋转调整。
调整方法:先记录当前节点的右孩子。然后,当前节点的右孩子指向当前节点孩子的左孩子;然后孩子节点的左孩子指向当前节点。
在这里插入图片描述

2.3 左右旋转

左右旋转,也叫左平衡调整。这种情况需要调整两次,先进行一次左旋转,再进行一次右旋转。如下图所示。
在这里插入图片描述

2.4 右左旋转

右左旋转,也称为有平衡操作。这种情况也需要调整两次,即先进行一次右旋转,再进行一次左旋转。
在这里插入图片描述

3 AVL的插入,旋转调整举例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. BST树 和 AVL树插入1-10后,对比

BST树插入1-10后,BST树变成了一个链表;AVL树则是一颗平衡二叉树。
在这里插入图片描述

5. AVL四种旋转操作,插入,删除代码实现

#include <iostream>
#include <functional>
using namespace std;// 定义AVL节点类型 
template <typename T>
class AVLTree
{
public:AVLTree() : root_(nullptr) { }// 插入操作void insert(const T &val){root_ = insert(root_, val);}// 删除操作void remove(const T & val){root_ = remove(root_, val);}private:// 定义AVL树节点类型 struct Node{Node(T data = T()):data_(data), left_(nullptr), right_(nullptr), height_(1){}T data_;Node *left_;Node *right_;int height_;};Node *root_;//int max(int a, int b){return a > b ? a : b;}/**	功能:返回node高度*/int height(Node *node){return node == nullptr ? 0 : node->height_;}/* *	功能:node节点进行右旋转,并返回旋转后的根节点**	参数:*		 node : 当前节点*	*   返回值: *		 返回旋转后的根节点*/Node *rightRotate(Node *node){Node *child = node->left_;node->left_ = child->right_;child->right_ = node;// 旋转后根节点和child节点发生了变化,所以要更新高度值。node->height_ = max(height(node->left_), height(node->right_)) + 1;node->height_ = max(height(child->left_), height(child->right_)) + 1;// 返回旋转后的根节点return child;}/*  功能:左旋转,并返回旋转后的根节点**	参数:*		 node : 根节点**   返回值:*		 返回旋转后的根节点*/Node *leftRotate(Node *node){Node *child = node->right_;node->right_ = child->left_;child->left_ = node;// 更新旋转后的高度值node->height_ = max(height(node->left_), height(node->right_)) + 1;child->height_ = max(height(child->left_), height(child->right_)) + 1;// 返回旋转后的根节点return child;}/**	功能:左右旋转,并把根节点返回**	参数:*		  node : 以参数node为旋转轴	*/		Node * leftBalance(Node *node){node->left_ = leftRotate(node->left_);  // 先对根节点左孩子进行左旋转return rightRotate(node);				// 再对,根节点右孩子进行右旋转。}/**	功能:右左旋转,并把根节点返回**	参数:*		  node : 以参数node为旋转轴*/Node * rightBalance(Node *node){node->right_ = rightRotate(node->right_);  // 以左孩子为根进行左旋return leftRotate(node);}/**	功能:node中插入节点,并返回新插入节点**/Node * insert(Node *node, const T & val){if (node == nullptr){return new Node(val);}if (node->data_ > val)   // 向当前节点的左子树中插入新节点,所以要判断,当前节点的左子树是否太高{node->left_ = insert(node->left_, val);  // 新插入的节点都在叶子节点上,所以下面回溯时,调整树的平衡状态。// 在回溯时候,判断节点是否失衡,如果node的左子树太高导致Node失衡了,// 当前在向左子树中插入节点,新节点在左子树的叶子中,只可能导致左子树失衡,不存在右子树失衡的情况,所以直接用左子树高度 减去 右子树高度。if (height(node->left_) - height(node->right_) > 1)  // 如果当前节点的左子树比右子树高{		 // 分两种情况来判断,一个是左孩子的左子树节点失衡,一个树右孩右子树节点失衡。if (height(node->left_->left_) >= height(node->left_->right_)){node = rightRotate(node);   // 用旋转后的根节点 代替根节点}else{node = leftBalance(node);}}}else if (node->data_ < val){node->right_ = insert(node->right_, val);// 在递归回溯时候,判断节点是否失衡,Node的右子树太高,node 失衡了if (height(node->right_) - height(node->left_) > 1){if (height(node->right_->right_) >= height(node->right_->left_))  // 1-10,插入节点9时会出现这种情况{node = leftRotate(node);}else{node = rightBalance(node);}}}else // 如果新插入节点与当前节点相等,不插入,不用再递归,直接回溯{;}// 更新节点高度。因为递归中增加了新节点,所以回溯时候,更新节点的高度。node->height_ = max(height(node->left_), height(node->right_)) + 1;return node; // rrturn后,直接回溯,不再向下递归}/**	功能:删除val节点**	参数:*		  node: 当前处理的根节点*		  val : 待删除的值*/Node * remove(Node *node,const T & val){if (node == nullptr){return nullptr;}if (node->data_ > val)    // 如果当前节点大于val,则从当前节点左孩子中查找{node->left_ = remove(node->left_, val);// 删除左子树的节点之后,可能造成右子树太高if (height(node->right_) - height(node->left_) > 1){// 右子树太高,分两种情况,第一:if (height(node->right_->right_) >= height(node->right_->left_)){// 右孩子的右子树太高node = leftRotate(node);}else{node = rightBalance(node);}}}else if (node->data_ < val){node->right_ = remove(node->right_, val);// 删除右节点后,可能造成左子树太高if (height(node->left_) - height(node->right_) > 1){// 如果左孩子的左子树失衡if (height(node->left_->left_) >= height(node->left_->right_)){node = rightRotate(node);}else{node = leftBalance(node);}}}else  // 删除节点,先删除两个孩子的节点,再删除一个孩子的节点{// 找到后,先处理两个孩子的节点,然后再删除一个孩子的节点。if (node->left_ != nullptr && node->right_ != nullptr){// 为了避免删除前驱和后继节点造成节点失衡,she高删除谁if (height(node->left_) >= height(node->right_)){// 删除	前驱Node *pre = node->left_;while (pre->right_ != nullptr){pre = pre->right_;}node->data_ = pre->data_;						// 覆盖值node->left_ = remove(node->left_, pre->data_);  // 删除前驱节点}else{// 删除后继节点Node *post = node->right_;while (post->right_ != nullptr){post = post->left_;}node->data_ = post->data_;node->right_ = remove(node->right_, post->data_);  // 删除后继节点}}else  // 最多有一个孩子节点{if (node->left_ != nullptr){Node *left = node->left_;delete node;return left;}else if (node->right_ != nullptr){Node *right = node->right_;delete node;return right;}else{return nullptr;}}}// 更新节点高度node->height_ = max(height(node->left_), height(node->right_)) + 1;return node;}
};int main()
{AVLTree<int> avl;for (int i = 1; i < 11; i++){avl.insert(i);}avl.remove(6);system("pause");return 0;
}

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

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

相关文章

【宝塔面板安装与配置、Redis安装与配置、MySQL安装与配置】

提示&#xff1a;宝塔面板下载地址&#xff1a;https://www.bt.cn/new/download.html 文章目录前言一、快速迁移二、设置固定ip一.保证可以连接网络二.设置固定ip三、搭建宝塔面板四、做好备份五、安装Redis六、安装MySQL一、8.0版本以下二、8.0版本以上三、安全组开放端口四、…

《web课程设计》 基于HTML+CSS+JavaScript实现中国水墨风的小学学校网站模板(6个网页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

安装OpenGL

提示错误信息&#xff1a; (base) C:\Users\Tina\PycharmProjects\FunnyToys-main>conda install opengl Collecting package metadata (current_repodata.json): done Solving environment: failed with initial frozen solve. Retrying with flexible solve. Collecting…

设置一个不能被继承的类

小屋杂谈&#xff0c;记录日常 方法1&#xff1a; 如果想让这个类不能被继承&#xff0c;可以把这个类的构造函数设置成私有&#xff0c;这样子类去继承他构造就会报错&#xff0c;这样的话这个类就是不能被继承的&#xff0c;如果需要用这个类的对象的话&#xff0c;在基类里…

设备安装CoreELEC系统,并配置遥控

目录0. 前言CoreELEC简介动机硬件1.准备工作1.1下载镜像1.2 制作启动U盘2.安装CoreELEC2.1 从U盘启动2.2 CoreELEC写入盒子emmc3.设置遥控器本文原首发于zdm&#xff0c;由于该平台审核机制出现问题且编辑器极其不好用&#xff0c;所以发布于此 仅作为记录操作的用途 0. 前言 …

时间工具类-- LocalDateTimeUtil详解

LocalDateTimeUtil 对时间进行操作的时候&#xff0c;使用LocalDateTimeUtil工具类可以大大提高使用的效率&#xff0c;具体的方法可以看下图&#xff1a; 具体的使用方法都在图中说明&#xff0c;主要是方便LocalDataTime的使用及操作 LocalDataTime的基本用法 基本用法 /…

00_linux_最简单构建字符设备 2.4版本之前使用

背景:怎么构建一个最简单的字符设备驱动并且可以使用app进行操作 名称大致意思设备proc/devices/设备名称 简单来说 insmode出来的设备节点/dev/xxx 对这个设备进行操作的文件 mknode使用主次设备号对设备关联 大致方法 1.写驱动文件(file_operation),构造对应的read write 函…

叠氮荧光染料:Azide-FL-BDP|1379771-95-5|BDP FL N3叠氮

BDP FL叠氮化物是一种类似于BODIPY FL叠氮化物的荧光染料&#xff0c;是一种具有点击化学性质的荧光染料。该荧光团是硼二吡咯甲基类荧光染料的代表&#xff0c;在水环境中具有较高的量子产率。azide系列产品包括可用于进一步连接的azide-acid&#xff1b;azide-amine&#xff…

Faster R-CNN详解

Faster R-CNN Faster R-CNN是作者Ross Girshick继Fast R-CNN后的又一力作。使用VGG16作为网络的backbone&#xff0c;推理速度在GPU上达到5fps(包括候选区域的生成)&#xff0c;准确率也有进一步的提升。在2015年的ILSVRC以及COCO竞赛中获得多个项目的第一名。 Faster R-CNN算…

使用星凸随机超曲面模型对扩展对象和分组目标进行形状跟踪(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

【电源专题】案例:不导这颗MOS管的原因是在电路上不通用?

本案例发生在MOS管替代料导入时。正常情况下在替代料导入、部品导入的时候,我们需要查看规格书。怎么查找规格书可以看文章【电子通识】芯片资料查询方法 对于一些关键的信息我们要做对比,一般来说要通过列表进行对比。但因为不同的供应商的测试标准不同,有很多是很难对比的…

浅析数据仓库和建模理论

第一章 认识数据仓库 1.1 数据仓库概念 数据仓库&#xff0c;英文名称为 Data Warehouse&#xff0c;可简写为 DW 或 DWH。数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所有类型数据支持的战略集合。它是单个数据存储&#xff0c;出于分析性报告和决…

第41讲:MySQL内置的QL性能分析工具

文章目录1.SQL性能分析的概念2.分析数据库中SQL的执行频率3.数据库中的慢查询日志3.1.开启慢查询日志功能3.2.模拟慢SQL查询观察日志内容4.Profile查看SQL每个阶段的耗时4.1.开启Profile操作4.2.随便执行一些查询语句4.3.查询执行SQL的耗时4.4.查询某一条SQL每个阶段的耗时4.5.…

Java项目:jsp+servlet实现的新闻发布系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目分为前后台&#xff1b; 前台主要功能为&#xff1a; 首页、娱乐新闻、经济新闻、文化新闻、小道新闻、用户评价等&#xff1b; 后台主要…

目标检测论文解读复现之二十:基于改进Yolov5的地铁隧道附属设施与衬砌表观病害检测方法

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0…

ipv6地址概述——配置ipv6

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…

TMS Echo数据复制的Delphi框架

TMS Echo数据复制的Delphi框架 TMS Echo是用于数据复制的Delphi框架。它是TMS Business产品阵容的一部分&#xff0c;它取决于TMS Aurelius的运营。 TMS Echo允许您至少拥有两个数据库并在它们之间同步信息。您对单个客户数据库所做的更改(插入、更新、删除)可能会传输到其他数…

jenkins关联github

将Jenkins和github关联起来&#xff0c;实现自动化集成 GitHub侧 1、生成secret.txt secret在github上被称为token 进去GitHub --> Settings --> Developer settings --> Personal access tokens -> Generate new token创建一个新的token,勾选两处标红的地方 点…

COLMAP生成MVSNet数据集

一. colmap2mvsnet.py COLMAP可以给图像数据集标定一套相机外参及视图选择。如果想用COLMAP导出的结果输入MVSNet测试&#xff0c;需要把数据集&#xff08;图片、相机参数等&#xff09;转化为MVSNet的输入格式。MVSNet的作者yaoyao在Github上提供了colmap2mvsnet.py代码&…

Jsoup爬虫入门实战

一、Jsoup介绍 jsoup 是一款基于 Java 的HTML解析器&#xff0c;它提供了一套非常省力的API&#xff0c;不但能直接解析某个URL地址、HTML文本内容&#xff0c;而且还能通过类似于DOM、CSS或者jQuery的方法来操作数据&#xff0c;所以 jsoup 也可以被当做爬虫工具使用。 相关…