数据结构: 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 二、…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...