当前位置: 首页 > news >正文

【平衡二叉树】AVL树(双旋)

图片名称
🎉博主首页: 有趣的中国人

🎉专栏首页: C++进阶

🎉其它专栏: C++初阶 | Linux | 初阶数据结构

在这里插入图片描述

小伙伴们大家好,本片文章将会讲解AVL树左双选和右双旋的相关内容。


如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!

文章目录

  • `1. 左右双旋`
  • `1. 右左双旋`
  • `3. AVL的验证`
  • `3. AVL的验证`
  • `3. AVL的性能`



1. 左右双旋


⚡出现情况
在这里插入图片描述

1. 此处在30的左子树或者右子树新增节点都会引发旋转;
2. 如果单纯的对根节点进行右单旋,并不能解决左边高的问题,会变成右边高,所以要进行双旋,步骤如下:

1. 先对parent->left节点进行左单旋

在这里插入图片描述

2. 再对根节点进行右单旋

在这里插入图片描述
完整步骤
在这里插入图片描述

我们假设顶端节点叫做parentparent->left 叫做subLsubL->right 叫做subLR


左右双旋后满足二叉搜索树的性质:

左右双旋后,实际上就是让subLR的左子树和右子树,分别作为subLparent的右子树和左子树,再让subLparent分别作为subLR的左右子树,最后让subLR作为整个子树的根。

1. subLR的左子树当中的结点本身就比subL的值大,因此可以作为subL的右子树。

2. subLR的右子树当中的结点本身就比parent的值小,因此可以作为parent的左子树。

3. 经过步骤1、2后,subL及其子树当中结点的值都就比subLR的值小,而parent及其子树当中结点的值都就比subLR的值大,因此它们可以分别作为subLR的左右子树。


左右双旋后,平衡因子的更新随着subLR原始平衡因子的不同分为以下三种情况:

1、subLR原始平衡因子是-1时,左右双旋后parent、subL、subLR的平衡因子分别更新为1、0、0
在这里插入图片描述


2、subLR原始平衡因子是1时,左右双旋后parent、subL、subLR的平衡因子分别更新为0、-1、0
在这里插入图片描述


3、subLR原始平衡因子是0时,左右双旋后parent、subL、subLR的平衡因子分别更新为0、0、0
在这里插入图片描述

代码如下:

void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;//1、以subL为旋转点进行左单旋RotateL(subL);//2、以parent为旋转点进行右单旋RotateR(parent);if (bf == -1){subL->_bf = 0;parent->_bf = 1;subLR->_bf = 0;}else if (bf == 1){subL->_bf = -1;parent->_bf = 0;subLR->_bf = 0;}else if (bf == 0){subL->_bf = subLR->_bf = parent->_bf = 0;}else {assert(false);}
}


1. 右左双旋


⚡出现情况

在这里插入图片描述

1. 此处在60的左子树或者右子树新增节点都会引发旋转;
2. 如果单纯的对根节点进行左单旋,并不能解决右边高的问题,会变成左边高,所以要进行双旋,步骤如下:

1. 先对subR节点进行右单旋

在这里插入图片描述

2. 对parent节点进行左单旋

在这里插入图片描述
3. 完整步骤

在这里插入图片描述

右左双旋后满足二叉搜索树的性质:

右左双旋后,实际上就是让subRL的左子树和右子树,分别作为parent和subR的右子树和左子树,再让parent和subR分别作为subRL的左右子树,最后让subRL作为整个子树的根。

1、subRL的左子树当中的结点本身就比parent的值大,因此可以作为parent的右子树。

2、subRL的右子树当中的结点本身就比subR的值小,因此可以作为subR的左子树。

3、经过步骤1、2后,parent及其子树当中结点的值都就比subRL的值小,而subR及其子树当中结点的值都就比subRL的值大,因此它们可以分别作为subRL的左右子树。


右左双旋后,平衡因子的更新随着subRL原始平衡因子的不同分为以下三种情况:

1、subRL原始平衡因子是1时,右左双旋后parent、subR、subRL的平衡因子分别更新为-1、0、0
在这里插入图片描述


2、subRL原始平衡因子是-1时,右左双旋后parent、subR、subRL的平衡因子分别更新为0、1、0
在这里插入图片描述


3、subRL原始平衡因子是0时,左右双旋后parent、subR、subRL的平衡因子分别更新为0、0、0
在这里插入图片描述

代码如下:

void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);if (bf == 1){subR->_bf == 0;parent->_bf = -1;subRL->_bf = 0;}else if (bf == -1){subR->_bf = 1;parent->_bf = 0;subRL->_bf = 0;}else if (bf == 0){subR->_bf = parent->_bf = subRL->_bf = 0;}else {assert(false);}
}


3. AVL的验证


AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:

  1. 验证其为二叉搜索树
    • 如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
  2. 验证其为平衡树
    • 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
    • 节点的平衡因子是否计算正确

详解代码:

public:void InOrder()
{_InOrder(_root);
}int Size()
{_Size(_root);
}int Height()
{_Height(_root);
}bool IsBalanceTree()
{return _IsBalanceTree(_root);
}private:bool _IsBalanceTree(Node* root)
{if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 计算左右子树高度差绝对值int dec = abs(leftHeight - rightHeight);// 如果比1大说明不平衡if (dec > 1){cout << root->_kv.first << endl;return false;}// 检查平衡因子是否计算正确if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << endl;return false;}return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
int _Height(Node* root)
{if (root == nullptr){return 0;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return max(leftHeight, rightHeight) + 1;
}int _Size(Node* root)
{if (root == nullptr){return 0;}return _Size(root->_left) + _Size(root->_right) + 1;
}void _InOrder(Node* root)
{if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);
}

3. AVL的验证


⚡验证示例1

int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};

验证代码:

void AVLTest1()
{AVLTree<int, int> t;int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };for (auto& e : a){t.Insert({ e,e });cout << "Insert:" << e << "->" << t.IsBalanceTree() << endl;}t.InOrder();
}

在这里插入图片描述

⚡验证示例2

int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };

验证代码:

void AVLTest1()
{AVLTree<int, int> t;int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto& e : a){t.Insert({ e,e });cout << "Insert:" << e << "->" << t.IsBalanceTree() << endl;}t.InOrder();
}

在这里插入图片描述



3. AVL的性能


AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 l o g 2 ( N ) log_2 (N) log2(N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

相关文章:

【平衡二叉树】AVL树(双旋)

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; C进阶 &#x1f389;其它专栏&#xff1a; C初阶 | Linux | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解AVL树的左双选和右双旋的相关内容。 如果看到最后您觉得这篇文章写…...

【保姆级介绍自动化的讲解】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…...

【大数据面试题】27 讲下Doris的物化视图

一步一个脚印&#xff0c;一天一道面试题。 物化视图概念 物化视图&#xff0c;顾名思义&#xff0c;是将一个查询的结果预先计算并存储为物理表的形式。这意味着&#xff0c;原本需要在运行时动态执行的复杂查询&#xff0c;现在变成了直接从已经计算好的结果表中读取数据&a…...

kylin 使用心得

Kylin操作系统是一种基于Linux的操作系统&#xff0c;主要在中国使用&#xff0c;由中国国内的开发团队维护。它的目标是为了提供一个稳定、安全、易于使用的操作环境。以下是一些用户可能基于Kylin操作系统的使用心得&#xff1a; 1. **界面友好**&#xff1a;Kylin操作系统通…...

在线音乐系统

文章目录 在线音乐系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目&#xff08;9.9&#xffe5;带走&#xff09; 在线音乐系统 一、项目演示 音乐网站 二、项目介绍 基于springbootvue的前后端分离在线音乐系统 登录角色 : 用户、管理员 用…...

LeetCode算法题:49. 字母异位词分组(Java)

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", …...

第五课,输入函数、布尔类型、比较运算和if判断

一&#xff0c;输入函数input() 与输出函数print()相对应的&#xff0c;是输入函数input()&#xff0c;前者是把程序中的数据展示给外界&#xff08;比如电脑屏幕上&#xff09;&#xff0c;而后者是把外界&#xff08;比如键盘&#xff09;的数据输入进程序中 input()函数可…...

数学建模——线性回归模型

目录 1.线性回归模型的具体步骤和要点&#xff1a; 1.收集数据&#xff1a; 2.探索性数据分析&#xff1a; 3.选择模型&#xff1a; 4.拟合模型&#xff1a; 5.评估模型&#xff1a; 1.R平方&#xff08;R-squared&#xff09;&#xff1a; 2.调整R平方&#xff08;Ad…...

景源畅信:抖音小店比较冷门的品类分享?

在抖音小店的世界里&#xff0c;热门品类总是吸引着众多商家和消费者的目光。然而&#xff0c;就像星空中的繁星&#xff0c;虽不那么耀眼却依然存在的冷门品类同样值得我们关注。它们或许不似服装、美妆那样日进斗金&#xff0c;但正是这些小众市场的存在&#xff0c;为平台带…...

java项目之企业资产管理系统(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的企业资产管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 管理员功能有个人中心&…...

[ardunio ide导入blinker库]

1 blinker库下载地址 https://github.com/blinker-iot/blinker-library2 导入方法一 zip导入 项目 -> 导入库 ->添加.zip库 3 导入方法二...

Llama 3 超级课堂 -笔记

课程文档&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 课程视频&#xff1a;https://space.bilibili.com/3546636263360696/channel/series 1 环境配置 1.1 创建虚拟环境,名为&#xff1a;llama3 conda create -n llama3 python3.10 1.2 下载、安装 pyt…...

Leetcode 第 129 场双周赛题解

Leetcode 第 129 场双周赛题解 Leetcode 第 129 场双周赛题解题目1&#xff1a;3127. 构造相同颜色的正方形思路代码复杂度分析 题目2&#xff1a;3128. 直角三角形思路代码复杂度分析 题目3&#xff1a;3129. 找出所有稳定的二进制数组 I思路代码复杂度分析 题目4&#xff1a;…...

队列的讲解

队列的概念 队列:只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头 一端进另一端出 也就是可以做到&#xff0c;先…...

算法学习笔记(LCA)

L C A LCA LCA&#xff1a;树上两个点的最近公共祖先。&#xff08;两个节点所有公共祖先中&#xff0c;深度最大的公共祖先&#xff09; L C A LCA LCA的性质&#xff1a; 在所有公共祖先中&#xff0c; L C A ( x , y ) LCA(x,y) LCA(x,y)到 x x x和 y y y的距离都最短。 x …...

记一次苹果appstore提审拒审问题1.2

有关苹果appstore审核1.2问题的处理方案 2023.8.6苹果回复 Bug Fix Submissions The issues weve identified below are eligible to be resolved on your next update. If this submission includes bug fixes and youd like to have it approved at this time, reply to thi…...

在做题中学习(59):除自身以为数组的乘积

238. 除自身以外数组的乘积 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;前缀积和后缀积 思路&#xff1a;answer中的每一个元素都是除自己以外所有元素的和。那就处理一个前缀积数组和后缀积数组。 而前缀积(f[i])是&#xff1a;[0,i-1]所有元素的乘积 后缀…...

centos 把nginx更新到最新版本

yum install epel-release # 添加 EPEL 软件仓库&#xff0c;这是 Nginx 官方软件仓库的依赖项 yum install yum-utils # yum-utils 包含了 yum-config-manager 工具&#xff0c;它可以让您轻松地启用、禁用或配置 yum 软件仓库 vi /etc/yum.repos.d/nginx.repo # 增加以下内容…...

01.认识HTML及常用标签

目录 URL&#xff08;统一资源定位系统&#xff09; HTML&#xff08;超文本标记语言&#xff09; 1&#xff09;html标签 2&#xff09;head标签 3&#xff09;title标签 4&#xff09;body标签 标签的分类 DTD文档声明 基础标签 1&#xff09;H系列标签 2&#xff09…...

从零开始:C++ String类的模拟实现

文章目录 引言1.类的基本结构2.构造函数和析构函数3.基本成员函数总结 引言 在C编程中&#xff0c;字符串操作是非常常见且重要的任务。标准库中的std::string类提供了丰富且强大的功能&#xff0c;使得字符串处理变得相对简单。然而&#xff0c;对于学习C的开发者来说&#x…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...