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

【数据结构】平衡二叉树(AVL树)

目录

前言

一、AVL树概念

二、AVL树节点定义

 三、AVL树插入

1. 按照二叉搜索树的方式插入新节点

2. 维护节点的平衡因子与调整树的结构

 a. 新节点插入较高左子树的左侧---左左:右单旋

b. 新节点插入较高右子树的右侧---右右:左单旋

c. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

d. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

四、AVL树删除

附录:AVL树实现参考代码 


前言

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查 找元素相当于在顺序表中搜索元素,效率低下。

因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年发明了一种方法,用以解决上述问题。


一、AVL树概念

AVL 树是一种平衡二叉树,得名于其发明者的名字( Adelson-Velskii 以及 Landis)。(可见名字长的好处,命名都能多占一个字母出来)。平衡二叉树递归定义如下:

  • 左右子树的高度差小于等于 1。
  • 其每一个子树均为平衡二叉树。

 为了使AVL树保持平衡,在节点中增加了一个平衡因子作为节点属性。当树发生变化时,就通过维护平衡因子与改变树的结构来使树保持平衡。

二、AVL树节点定义

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;std::pair<K, V> _kv;int _bf; //balance factorAVLTreeNode(const std::pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}
};

 三、AVL树插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么 AVL树的插入过程可以分为两步:

1. 按照二叉搜索树的方式插入新节点

参考二叉搜索树。

【数据结构】二叉搜索树-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lyhv_v/article/details/139243506

2. 维护节点的平衡因子与调整树的结构

 cur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent 的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:

  1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
  2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可

此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2

  1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整成0,此时满足 AVL树的性质,插入成功
  2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,此 时以pParent为根的树的高度增加,需要继续向上更新
  3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转处理

 a. 新节点插入较高左子树的左侧---左左:右单旋

Node* RotateR(Node* parent)
{Node* sub = parent->_left;Node* subR = sub->_right;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{Node* up = parent->_parent;if (up->_kv.first > sub->_kv.first)up->_left = sub;elseup->_right = sub;sub->_parent = up;}parent->_left = subR;if (subR != nullptr)subR->_parent = parent;sub->_right = parent;parent->_parent = sub;parent->_bf = 0;sub->_bf = 0;return sub;
}

b. 新节点插入较高右子树的右侧---右右:左单旋

Node* RotateL(Node* parent)
{Node* sub = parent->_right;Node* subL = sub->_left;if (parent == _root){_root = sub;sub->_parent = nullptr;				}else{Node* up = parent->_parent;if (up->_kv.first > sub->_kv.first)up->_left = sub;elseup->_right = sub;sub->_parent = up;}parent->_right = subL;if (subL != nullptr)subL->_parent = parent;sub->_left = parent;parent->_parent = sub;parent->_bf = 0;sub->_bf = 0;return sub;
}

c. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

Node* RotateLR(Node* parent)
{Node* child = parent->_left;Node* sub = child->_right;Node* subL = sub->_left;Node* subR = sub->_right;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{Node* up = parent->_parent;if (up->_kv.first > sub->_kv.first)up->_left = sub;elseup->_right = sub;sub->_parent = up;}sub->_right = parent;parent->_parent = sub;sub->_left = child;child->_parent = sub;parent->_left = subR;if (subR != nullptr)subR->_parent = parent;child->_right = subL;if (subL != nullptr)subL->_parent = child;if (sub->_bf == 1){parent->_bf = 0;child->_bf = -1;}else if (sub->_bf == -1){parent->_bf = 1;child->_bf = 0;}else{parent->_bf = 0;child->_bf = 0;}sub->_bf = 0;return sub;
}

d. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

Node* RotateRL(Node* parent)
{Node* child = parent->_right;Node* sub = child->_left;Node* subL = sub->_left;Node* subR = sub->_right;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{Node* up = parent->_parent;if (up->_kv.first > sub->_kv.first)up->_left = sub;elseup->_right = sub;sub->_parent = up;}sub->_left = parent;parent->_parent = sub;sub->_right = child;child->_parent = sub;parent->_right = subL;if (subL != nullptr)subL->_parent = parent;child->_left = subR;if (subR != nullptr)subR->_parent = child;if (sub->_bf == 1){parent->_bf = -1;child->_bf = 0;}else if (sub->_bf == -1){parent->_bf = 0;child->_bf = 1;}else{parent->_bf = 0;child->_bf = 0;}sub->_bf = 0;return sub;
}

四、AVL树删除

因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不 错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。

具体实现可参考《算法导论》或《数据结构-用面向对象方法与C++描述》殷人昆版。

附录:AVL树实现参考代码 

AVLTree · 梁羽赫/cpp_advanced - 码云 - 开源中国 (gitee.com)icon-default.png?t=N7T8https://gitee.com/yuhe-liang/cpp_advanced/tree/master/AVLTree

相关文章:

【数据结构】平衡二叉树(AVL树)

目录 前言 一、AVL树概念 二、AVL树节点定义 三、AVL树插入 1. 按照二叉搜索树的方式插入新节点 2. 维护节点的平衡因子与调整树的结构 a. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 b. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 c. 新节点插入…...

python数据文件处理库-pandas

内容目录 一、pandas介绍二、数据加载和写出三、数据清洗四、数据转换五、数据查询和筛选六、数据统计七、数据可视化 pandas 是一个 Python提供的快速、灵活的数据结构处理包&#xff0c;让“关系型”或“标记型”数据的交互既简单又直观。 官网地址: https://pandas.pydata.o…...

stm32 h5 串口采用DMA循环BUFF接收数据

当使用STM32H5系列的MCU进行串口&#xff08;USART&#xff09;通信&#xff0c;并希望使用DMA&#xff08;Direct Memory Access&#xff09;进行循环缓冲区&#xff08;Circular Buffer&#xff09;接收数据时&#xff0c;你需要进行以下配置步骤&#xff1a; 初始化串口&…...

海外媒体通稿:9个极具创意的旅游业媒体推广案例分享-华媒舍

如今&#xff0c;旅游业正迅速发展&#xff0c;媒体推广成为吸引游客的关键。为了更好地展示旅游目的地&#xff0c;许多创意而富有创新的媒体推广策略应运而生。本文将介绍九个极富创意的旅游业媒体推广案例&#xff0c;为广大从业者带来灵感和借鉴。 1. 视频系列&#xff1a;…...

接口自动化框架封装思想建立(全)

httprunner框架&#xff08;上&#xff09; 一、什么是Httprunner&#xff1f; 1.httprunner是一个面向http协议的通用测试框架&#xff0c;以前比较流行的是2.X版本。 2.他的思想是只需要维护yaml/json文件就可以实现接口自动化测试&#xff0c;性能测试&#xff0c;线上监…...

char [] 赋新值

在C语言中&#xff0c;字符数组&#xff08;char []&#xff09;的值可以通过多种方式进行赋值。以下是一些常见的方法&#xff1a; 1、直接初始化&#xff1a; char str[50] "Hello, World!";2、使用strcpy()函数&#xff1a; char str[50]; strcpy(str, "…...

matlab计算图像信噪比SNR

直接上源码: close all clear all clc% 读取图像 I = imread(lena.bmp);I = rgb2gray(I); J =imnoise(I, salt & pepper, 0.001);...

DP读书:如何使用badge?(开源项目下的标咋用)

最近在冲论坛&#xff0c;很少更一些内容了。但遇到了一个真的有趣的&#xff1a; 开源项目下&#xff0c;蓝蓝绿绿的标是怎么用的呢&#xff1f; 这是我的主页Readme&#xff0c;在看一些NXP的主仓时&#xff0c;突然发现没有这个玩&#xff0c;就自己整了个 再比如我的CSDN专…...

使用JavaScript实现网页通知功能

如何使用js来实现网页通知功能。即使在用户浏览其他页面时&#xff0c;也能向他们推送通知信息。 废话不多说直接上代码 function showAutoNotification() {if ("Notification" in window) {Notification.requestPermission().then(function(permission) {if (permis…...

前端--导出

这边记录我们公司后端做的导出接口和前端是如何对接的 这边的技术栈是&#xff1a; 1&#xff1a; react 2&#xff1a; fetch 第一步&#xff1a;简单封装--导出界面 import { DrawerForm } from ant-design/pro-components; import { CloseOutlined } f…...

【数据库系统概论】触发器

【数据库系统概论】触发器 概述 在数据库系统中&#xff0c;触发器&#xff08;Trigger&#xff09;是一种特殊的存储过程&#xff0c;当特定事件在数据库表上发生时&#xff0c;会自动执行。触发器主要用于确保数据的完整性、一致性和实现复杂的业务规则。触发器是由用户定义…...

小白跟做江科大32单片机之按键控制LED

原理部分 1.LED部分使用的是这样的连接方式 2.传感器模块的电路图 滤波电容如果接地&#xff0c;一般用于滤波&#xff0c;在分析电路时就不用考虑。下面这个电路就是看A端和B端哪端的拉力大&#xff0c;就能把电压值对应到相应的电压值 比较器部分 如果A端电压>B端电压&am…...

每天写java到期末考试(6.6)-java文件输入输出流实验

1、用字节流读写二进制文件 要求:用DataOutputStreamFileOutputStream类将1,2,…,100,这100个数字写入到文件 d:\out1.bin里,然后再用DatalnputStreamFilelnputStream类将d:\out1.bin的内读出来,并输出到屏幕上。 用DataOutputStreamFileOutputStream写入二进制数据时,直接调…...

Word2021中的The Mathtype DLL cannot be found问题解决(office 16+mathtype7+非初次安装)

问题描述&#xff0c;我的问题发生在word中无法使用自定义功能区中的mathtype 我的环境是&#xff1a;W11Word2021mathtype7 因为我是第二次安装mathtype7&#xff0c;所以我怀疑是因为没有卸载干净&#xff0c;于是我参考了下面这篇文章的做法 参考文章 1.首先重新卸载当前的…...

【Android面试八股文】在Java中传参数时是将值进行传递,还是传递引用?

在Java中传参数时是将值进行传递,还是传递引用? 这道题想考察什么? 是否了解什么是值传递和引用传递与真实场景使用,是否熟悉什么是值传递和引用传递在工作中的表现是什么? 考察的知识点 什么是值传递和引用传递的概念,两者对开发中编写的代码的影响 考生应该如何回…...

神经网络 torch.nn---Linear Layers(nn.Linear)

torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn — PyTorch 2.3 documentation nn.Linear torch.nn.Linear(in_features, out_features, biasTrue, deviceNone, dtypeNone) 参数&#xff1a; in_features - 每个输入样本的大小out_features - 每个输出…...

PPT视频如何16倍速或者加速播放

有两种方式&#xff0c;一种是修改PPT本身&#xff0c;这种方式非常繁琐&#xff0c;不太推荐&#xff0c;还有一种就是修改视频本身&#xff0c;直接让视频是16倍速的视频即可。 如何让视频16倍速&#xff0c;我建议人生苦短&#xff0c;我用Python&#xff0c;几行代码&…...

【ai】DeepStream 简介

NVIDIA Metropolis 平台。 NVIDIA 大都会 利用视觉 AI 将来自数万亿物联网设备的数据转化为有价值的见解。 NVIDIA Metropolis 是一个应用程序框架、一套开发工具和合作伙伴生态系统,它将视觉数据和 AI 结合在一起,以提高各行各业的运营效率和安全性。它有助于理解数万亿个…...

如何学习使用淘宝API?淘宝API运营场景

学习使用淘宝API涉及对其功能、分类、调用方法及实际应用的综合理解。下面按部分详细解释如何系统地学习和掌握淘宝API的使用&#xff1a; 淘宝API接口入门 了解淘宝开放平台&#xff1a;淘宝开放平台为开发者提供了一个可以与淘宝数据进行交互的平台&#xff0c;涵盖了丰富的A…...

Java 面试题:Java 的动态代理是基于什么原理?

编程语言通常有各种不同的分类角度&#xff0c;动态类型和静态类型就是其中一种分类角度&#xff0c;简单区分就是语言类型信息是在运行时检查&#xff0c;还是编译期检查。 与其近似的还有一个对比&#xff0c;就是所谓强类型和弱类型&#xff0c;就是不同类型变量赋值时&…...

深入Linuxptp:ptp4l与E2E模式下的状态机与报文处理流程剖析

1. Linuxptp与ptp4l基础认知 第一次接触PTP协议时&#xff0c;我被那些专业术语搞得晕头转向。直到在实验室里用示波器抓到实际报文&#xff0c;才真正理解这个时间同步协议的精妙之处。Linuxptp作为开源实现&#xff0c;其中的ptp4l守护进程就像个尽职的交通警察&#xff0c;协…...

实战应用:基于快马平台构建支持实时协作的团队版pencil设计工具

今天想和大家分享一个实战项目&#xff1a;基于InsCode(快马)平台构建团队协作版pencil设计工具的经历。这个工具最终成为了我们产品团队的需求沟通神器&#xff0c;特别适合中小团队快速搭建轻量级设计协作环境。 为什么需要这个工具 我们团队经常遇到设计稿反复修改、版本混乱…...

华为2288H V3服务器iBMC配置全攻略:从默认密码到ESXi安装一步到位

华为2288H V3服务器iBMC与ESXi部署实战指南 对于企业IT基础设施团队而言&#xff0c;华为2288H V3服务器的灵活配置与高效管理能力使其成为数据中心建设的理想选择。本文将深入解析从基础配置到虚拟化平台部署的全流程&#xff0c;特别针对iBMC智能管理系统和VMware ESXi安装提…...

告别单片机!用Multisim 10.0和74LS192芯片,手把手教你搭一个30秒倒计时器(附完整电路图)

数字电路实战&#xff1a;用Multisim与74LS192打造精准30秒倒计时器 在电子设计领域&#xff0c;倒计时器是一个经典而实用的项目。传统上&#xff0c;许多初学者会直接选择单片机方案&#xff0c;认为编程控制更为简单。但真正理解数字电路的工作原理&#xff0c;掌握硬件层面…...

MySQL 8.0隐藏技能:不用.frm文件,用Go语言工具+ALTER TABLE命令直接解析.ibd恢复表结构

MySQL 8.0数据恢复新思路&#xff1a;用Go语言逆向解析.ibd文件的技术实践 当数据库遭遇灾难性故障时&#xff0c;.frm文件的消失让MySQL 8.0的数据恢复变得更具挑战性。本文将带你深入InnoDB存储引擎的核心&#xff0c;探索一种不依赖传统.frm文件的全新恢复方案。 1. MySQL 8…...

ComfyUI-Florence2深度配置指南:如何高效解决视觉语言模型加载与文档问答难题

ComfyUI-Florence2深度配置指南&#xff1a;如何高效解决视觉语言模型加载与文档问答难题 【免费下载链接】ComfyUI-Florence2 Inference Microsoft Florence2 VLM 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Florence2 在人工智能视觉处理领域&#xff0c;F…...

113. 强制使用 Letsencrypt ECDSA 和 DNS-01 续期挑战的默认 HTTPS Rancher 证书

Environment 环境 2.9 Situation 地理位置A self-signed default Rancher certificate is currently used and will be migrated to a stronger Let’s Encrypt ECDSA-386 certificate using the DNS-01 renewal challenge. 目前使用自签名默认的牧场证书&#xff0c;并将通过…...

noTunes:守护macOS专注体验的开源工具

noTunes&#xff1a;守护macOS专注体验的开源工具 【免费下载链接】noTunes A simple macOS application that will prevent iTunes or Apple Music from launching. 项目地址: https://gitcode.com/gh_mirrors/no/noTunes 在数字工作环境中&#xff0c;音乐应用的自动启…...

AI赋能浏览器:通过快马平台生成智能扩展,实现网页内容自动总结与代码智能解释

最近在做一个很有意思的尝试&#xff1a;用AI给浏览器装上"智能大脑"。具体来说&#xff0c;是开发一个谷歌浏览器扩展&#xff0c;能够智能分析网页内容。这个扩展最酷的地方在于&#xff0c;它能自动识别你选中的是普通文本还是代码&#xff0c;然后分别给出摘要总…...

3分钟上手PCL2-CE:打造专属Minecraft启动环境的完整指南

3分钟上手PCL2-CE&#xff1a;打造专属Minecraft启动环境的完整指南 PCL2-CE社区版是一款开源游戏配置工具&#xff0c;致力于为Minecraft玩家提供高效、灵活的游戏环境管理方案。通过智能化配置和模块化设计&#xff0c;让玩家告别繁琐设置&#xff0c;轻松掌控游戏入口&…...