数据结构: AVL树
目录
1.AVL树的概念
2.AVL树的模拟实现
AVL树的结构定义
插入
对平衡因子的讨论
旋转
对旋转情况的讨论
1.单旋
1.1左单旋
1.2右单旋
2.双旋
2.1左右双旋
2.2右左双旋
检查是否是AVL树
1.AVL树的概念
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
2.AVL树的模拟实现
AVL树的结构定义
节点

AVLTree

插入
插入节点会影响祖先(全部或者部分) ==> 需要更新平衡因子 ==> 讨论是否调整
新增节点的位置进行讨论:
- cur == parent->right parent->bf++
- cur == parent->left parent->bf--
什么决定了是否要继续往上更新爷爷节点, 取决于parent所在的子树高度是否变化? 变了继续更新, 不变则不再更新
- a. parent->bf == 1 || parent->bf == -1 parent所在的子树变了.继续更新, 为什么? ==> 说明插入前parent->bf == 0 , 说明两边高度相等, 现在有一边高1, 说明parent的子一边高一边低, 高度变了.
- b. parent->bf ==2 || parent == -2 -> parent所在的子树不平衡了, 需要处理子树(旋转处理)
- c. parent->bf == 0, parent所在的子树高度不变, 不用继续往上更新, 这一次插入结束. 为什么? ==> 说明插入前parent->bf == 1 or -1 ,说明插入之前一边高一边低, 插入节点填上矮的一边, 它的高度不变.
代码(找到插入的位置):
对平衡因子的讨论

旋转
目的: 1.让子树平衡 2. 降低子树的高度
旋转的原则: 保持它继续是搜索树
对旋转情况的讨论
1.单旋
--细节:
--空节点的处理
--parent需要维护(对parent是否是根节点进行讨论) 处理subR/L
--平衡因子更新
1.1左单旋
parent->_bf == 2 && cur->_bf == 1
--旋转 ==> 处理parent ==>更新平衡因子(parent的parent需要讨论, 影响与subR/L的链接)
代码:
// 左单旋void RotateL(Node* pParent) {Node* subR = pParent->_pRight;Node* subRL = subR->_pLeft;Node* ppnode = pParent->_pParent;//旋转//把subR的左(subRL)给parent的右,parent变为subR的左,并处理它们的parentif (subRL) subRL->_pParent = pParent;pParent->_pRight = subRL;pParent->_pParent = subR;subR->_pLeft = pParent;if (pParent == _pRoot) //根节点{_pRoot = subR;subR->_pParent = nullptr;}else //非根节点{if (ppnode->_pLeft == pParent) {ppnode->_pLeft = subR;}else //ppnode->_pRight == pParent{ppnode->_pRight == subR;}subR->_pParent = ppnode;}//更新平衡因子pParent->_bf = subR->_bf = 0;}
1.2右单旋
parent->_bf == -2 && cur->_bf == -1
代码:
// 右单旋void RotateR(Node* pParent){Node* subL = pParent->_pLeft;Node* subLR = subL->_pRight;Node* ppnode = pParent->_pParent;//旋转//把subL的右(subLR)给parent, parent变为subL的右边, 并处理它们的parentif (subLR) subLR->_pParent = pParent;pParent->_pLeft = subLR;pParent->_pParent = subL;subL->_pRight = pParent;if (pParent == _pRoot) {_pRoot = subL;subL->_pParent = nullptr;}else {if (ppnode->_pLeft == pParent) {ppnode->_pLeft = subL;}else {ppnode->_pRight = subL;}subL->_pParent = ppnode;}//更新平衡因子subL->_bf = pParent->_bf = 0;}
2.双旋
--对单旋的复用 ==> 更新平衡因子
需要保存subRL/LR的平衡因子, 根据插入节点的位置, 进行更新
2.1左右双旋
代码:
// 左右双旋void RotateLR(Node* pParent) {Node* subL = pParent->_pLeft;Node* subLR = subL->_pRight;int bf = subLR->_bf;//旋转RotateL(pParent->_pLeft);RotateR(pParent);//更新平衡因子if (bf == -1) {pParent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1) {pParent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == 0) {pParent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else {assert(false);}}
2.2右左双旋
parent -> bf = 2 && cur -> bf = -1
代码:
// 右左双旋void RotateRL(Node* pParent) {Node* subR = pParent->_pRight;Node* subRL = subR->_pLeft;int bf = subRL->_bf;//右旋RotateR(pParent->_pRight);RotateL(pParent);//讨论平衡因子的更新if (bf == -1) {pParent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 1) {pParent->_bf = -1;subR->_bf = 0;subRL->_bf = 0;}else if (bf == 0) {pParent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else {assert(false);}}
检查是否是AVL树
1.各子树的高度差是否<=1
2.平衡因子是否正确(右子树-左子树高度判断)
代码:
// AVL树的验证bool IsAVLTree(){return _IsAVLTree(_pRoot);}根据AVL树的概念验证pRoot是否为有效的AVL树bool _IsAVLTree(Node* pRoot) {if (pRoot == nullptr)return true;//1.检查各子树的高度差是否小于1int left_h = _Height(pRoot->_pLeft);int right_h = _Height(pRoot->_pRight);if (right_h - left_h != pRoot->_bf) {cout << "平衡因子异常" << endl;}if (abs(left_h - right_h) > 1)return false;return _IsAVLTree(pRoot->_pLeft) && _IsAVLTree(pRoot->_pRight);}size_t _Height(Node* pRoot) {if (pRoot == nullptr) {return 0;}size_t left_h = _Height(pRoot->_pLeft) + 1;size_t right_h = _Height(pRoot->_pRight) + 1;return left_h > right_h ? left_h : right_h;}
效果:
1.正常情况:
2.屏蔽掉平衡因子的修改:
相关文章:
数据结构: AVL树
目录 1.AVL树的概念 2.AVL树的模拟实现 AVL树的结构定义 插入 对平衡因子的讨论 旋转 对旋转情况的讨论 1.单旋 1.1左单旋 1.2右单旋 2.双旋 2.1左右双旋 2.2右左双旋 检查是否是AVL树 1.AVL树的概念 当向二叉搜索树中插入新结点后,如果能保证每个结点…...
LeetCode-高频 SQL 50 题:连接 篇
目录 1378. 使用唯一标识码替换员工ID 题目描述: SQL语句: 1068. 产品销售分析 I 题目描述: SQL语句: 1581. 进店却未进行过交易的顾客 题目描述: SQL语句: 197. 上升的温度 题目描述࿱…...
操作系统备考学习 day10
操作系统备考学习 day10 第三章 内存管理3.2 虚拟内存管理3.2.1 虚拟内存的基本概念传统存储管理方式的特征、缺点局部性原理虚拟内存的定义和特征如何实现虚拟内存技术 3.2.2 请求分页管理方式页表机制缺页中断机构地址变换机构 3.2.3 页面置换算法最佳置换算法(OP…...
基于侏儒猫鼬优化的BP神经网络(分类应用) - 附代码
基于侏儒猫鼬优化的BP神经网络(分类应用) - 附代码 文章目录 基于侏儒猫鼬优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.侏儒猫鼬优化BP神经网络3.1 BP神经网络参数设置3.2 侏儒猫鼬算法应用 4.测试结果…...
ios safari 正则兼容问题
背景: 系统是自己开发的采购管理系统; 最近升级系统之后客户反馈部分苹果手机现在在进入单据界面的时候报错, 内容显示不全; 安卓手机正常; 苹果首页是之前有使用过系统的才不行, 如果是之前没有使用过系统, 现在也是可以(后面查证这一点可能不是很准确, 跟是否等过过系统…...
Win10下基于VS2015编译SQLite3源码
一、下载SQLite SQLite SQLite Download Page 下载红框部分的3个文件 提示:这里有个 sglite-autoconf-3420000.tar.gz 是免编译版,想省事就下载这个,但我自己用这个老是编译不过 所以我这里不推荐这个了 二、配置SQLite 打开vs 2015或者其他…...
Linux 指令学习
Linux 指令学习 以此为记录,也方便自己日后查看回顾! Linux命令基础格式 无论是什么命令,用于什么用途,在Linux中,命令有其通用的格式: command: 命令本身 options:[可选…...
前端渲染后端返回的HTML格式的数据
在日常开发中,经常有需要前端渲染后端返回页面的需求,对于不同数据结构,前端的渲染方式也不尽相同,本文旨在对各种情况进行总结。 后端返回纯html文件格式 数据包含html标签等元素,数据类型如下图: 前端通…...
身份证读卡器ubuntu虚拟机实现RK3399 Arm Linux开发板交叉编译libdonsee.so找不到libusb解决办法
昨天一个客户要在RK3399 Linux开发板上面使用身份证读卡器,由于没有客户的开发板,故只能用本机ubuntu虚拟机来交叉编译,用客户发过来的交叉编译工具,已经编译好libusb然后编译libdonsee.so的时候提示找不到libusb,报错…...
触想五代强固型工业一体机在近海船舶上的应用
1、行业发展背景 近海船舶的发展紧密关联着海上运输、渔业贸易、旅游开发、能源探测等多领域,带动区域经济、文化繁荣发展。 随着现代科学与信息技术在各行各业的作用增强,工业4.0带动的产业升级逐步渗透进船舶领域,在此背景下,船…...
Node-创建Web应用
题记 node创建web应用,以下是所有流程和代码 与php比较:使用 PHP 来编写后端的代码,需要 Apache 或者 Nginx 的 HTTP 服务器,并配上 mod_php5 模块和 php-cgi。 Node应用的组成 node应用由三部分组成: require 指令&a…...
Redis查找并删除key
redis安装在IP为x.x.x.x的服务器上 redis安装 第一步,安装编译工具及库文件。 命令:yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel 第二步,下载redis安装包。 命令:cd /usr/local/src wget ht…...
Spring Security认证架构介绍
在之前的Spring Security:总体架构中,我们讲到Spring Security整个架构是通过Bean容器和Servlet容器对过滤器的支持来实现的。我们将从过滤器出发介绍Spring Security的Servlet类型的认证架构。 1.AbstractAuthenticationProcessingFilter AbstractAut…...
提升代码重用性:模板设计模式在实际项目中的应用
在软件开发中,我们经常面临着相似的问题,需要使用相同的解决方法。当我们希望将这种通用的解决方法抽象出来,并在不同的情境中重复使用时,就可以使用设计模式中的模板模式(Template Pattern)。模板模式是一…...
11-k8s-service网络
文章目录 一、网络相关资源介绍二、开启ipvs三、nginx网络示例四、pod之间的访问示例五、service反向代理示例 一、网络相关资源介绍 Servcie介绍 Service是对一组提供相同功能的Pods的抽象,并为它们提供一个统一的入口。借助Service,应用可以方便的实现…...
MyBatisPlus(二十二)代码生成器
使用场景 使用代码生成器,根据数据库表,自动生成对应的 Entity,Mapper,Service,Controller 。 代码 依赖 两个依赖: 生成器依赖模板依赖 <dependency><groupId>com.baomidou</groupId&…...
git报错The project you were looking for could not be found 解决方式
问题描述: 使用git从远程仓库克隆项目到本地的时候。 git clone http://gitlab.com/project/xxxx.git出现这个问题:The project you were looking for could not be found. 原因分析: 你的账号没有项目的权限,你可以在浏览器输…...
“编辑微信小程序与后台数据交互与微信小程序wxs的使用“
引言 在现代移动应用开发中,微信小程序已经成为了一个非常流行和广泛使用的平台。为了使小程序能够展示丰富的内容和实现复杂的功能,与后台数据的交互是至关重要的。同时,微信小程序还提供了一种特殊的脚本语言——wxs,用于增强小…...
从Linux的tty_struct指针获取驱动上下文
背景 问题 前段时间开发一个tty驱动,用途是实现仪器对GPIB消息的接收、处理和上报。对于上报场景,下位机应用将上报内容写入一个驱动创建的tty设备,tty子系统将应用的输入转发给tty驱动,tty驱动将其转换成对SPI从设备࿰…...
PHP WAP餐厅点餐系统mysql数据库web结构apache计算机软件工程网页wamp
一、源码特点 PHP餐厅点餐系统是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 PHP WAP餐厅点餐系统 代码 https://download.csdn.net/download/qq_41221322/88440001 二、…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...









