AVL树大讲堂

news/2024/4/29 0:04:59/文章来源:https://blog.csdn.net/midslucky/article/details/129713426

1.基础概念介绍

首先在前面我们介绍了二叉搜索树,但是如果当存储的数据接近有序或者恰巧有序的时候,二叉搜索树将逐渐退化为单支树,导致搜索效率降低,因此我们的avl树便为了解决这一问题而诞生了

基础性质:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(右子树的高度减去左子树的高度),即可降低树的高度,从而减少平均搜索长度。

如图所示便是一棵典型的AVL树:

在这里插入图片描述

2.基础代码的复现

2.1基础结点
template<K,V>
class AVLTreeNode
{AVLTreeNode<K,V>* _left;AVLTreeNode<K,V>* _right;AVLTreeNode<K,V>* _parent;pair<K,V> _kv;int _bf; //平衡因子AVLTreeNode(const pair<K,V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};
2.2树内部的基础封装
template<k,v>
class AVLTree
{typedef AVLTreeNode<k,v> Node;AVLTree():_root(nullptr){}private:Node* _root;
}
2.3最麻烦的插入(此处先搭一个板子我们分两大部分进行讲解)

首先我们在这边先讲解一下大致思路。结合上面的代码我们可以看到相对比于普通的二叉搜索树而言,其结点中多了一个父结点的指针和一个平衡因子,而其本质上来说插入结点的规则要和二叉搜索树保持一致,那么这样思路便简单不少。首先我们先要保证其具备搜索二叉树的特性,其次每插入一个新的结点难免会造成平衡因子的变化,所以我们需要时时注意那些会发生改变的平衡因子,为此我们便需要写一个平衡因子的检查功能,并当平衡因子超过大于1或者小于-1时,采取相应措施,使其回归正常值

实际代码:

Insert(const pair<K,V>& kv)
{if(_root == nullptr){Node* newnode = new Node(_kv);return true;}Node* parent = nullptr;Node* cur = _root;while(cur){if(cur->_kv.first > kv.first)//注意这边给的值是pair,所以比较的时候需要这么写{parent = cur;cur = cur->_left;}if(cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv); //注意此处我直接用cur开,而没有在开一个新结点,省掉了cur的处理cur->_parent = parent;if(parent->_kv.first > kv.first){parent->left = cur;cur->_parent = parent;}else if{parent->riget = cur;cur->_parent = parent;}//到此处我们的插入就完成了//接下来我们需要开始控制平衡while(parent){if (cur == parent->_left)parent->_bf--;elseparent->_bf++;if(parent->_bf == 0) { break;}else if(parent->_bf == 1 || parent->_bf == -1){//这个时候明显会影响上面结点的平衡因子,所以需要往上找cur = parent;parent = parent->_parent;}else if(parent->_bf == 2 || parent->_bf == -2)//开始旋转处理{if (parent->_bf == -2 && cur->_bf == -1)//右单旋{RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1) // 左单旋{RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1)//左右双旋{RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1)//右左双旋{RotateRL(parent);}else{assert(false);}break;}else{// 说明插入更新平衡因子之前,树中平衡因子就有问题了assert(false);}}return true;
}

当然这有几个函数的代码这里没给,先不急我们先分析一下其原理。

3. 4种旋转的原理分析

1.右单旋

在这里插入图片描述

2.左右单旋

在这里插入图片描述

3.左单旋

在这里插入图片描述

4.右左单旋

在这里插入图片描述

ok仔细观察4幅图片可以很清晰的观察到整个过程**(看这段话之前请花时间多看看,拿1.2两幅图相对比,在拿3.4两幅图相对比)**

当然可以看出1.3两幅图最后插入的一个数都是插在了靠边的那棵子树,因此一次旋转后就能解决,而2.4是插在了靠边那棵子树的傍边,所以变有了一下的情况,而这4种情况可以说是囊括了所有的可能性。

4.个旋转的代码实现

1.右单旋
void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subL;elseparentParent->_right = subL;subL->_parent = parentParent;}subL->_bf = parent->_bf = 0;
}
2.左单旋
void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL){subRL->_parent = parent;}Node* parentParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parentParent->_left == parent)parentParent->_left = subR;elseparentParent->_right = subR;subR->_parent = parentParent;}subR->_bf = parent->_bf = 0;}
3.左右双旋
void RotateLR(Node* parent){RotateL(parent->_left);RotateR(parent);}
4.右左双旋
void RotateRL(Node* parent){RotateR(parent->_right);RotateL(parent);}

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

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

相关文章

Tone Mapping中luma滤波(降噪)对噪声放大的定性分析

Tone Mapping中luma滤波对噪声放大的定性分析 在tone mapping过程中&#xff0c;通常经过统计之后得到一条mapping曲线&#xff0c;记这条曲线为f(x)f(x)f(x)&#xff0c;mapping过程中&#xff0c;对于给定的点&#xff0c;假定其亮度为xxx&#xff0c;映射后为f(x)f(x)f(x)&…

虚拟机设置桥接模式:静态IP

一、下载virtual box并安装系统 链接&#xff1a;https://www.virtualbox.org/ 安装并配置Ubuntu桌面版&#xff1a;https://blog.csdn.net/Zhichao_Zhang/article/details/127142410?spm1001.2014.3001.5506 安装并配置CentOS7&#xff1a;https://blog.csdn.net/csp7321711…

【学习笔记】《Writing Science》14-21

文章目录14 Energizing Writing 充满活力的写作14.1. ACTIVE VERSUS PASSIVE VOICE 主动语态和被动语态14.1.1. Controlling Perspective 控制视角14.1.2. Hiding the Actor 隐藏演员14.2. FUZZY VERBS 模糊动词14.2.1. Fuzzy Hypotheses 模糊假设14.3. NOMINALIZATIONS 名词化…

自动化测试学习(七)-正则表达式,你真的会用吗?

目录 一、正则表达式在python中如何使用 二、用正则表达式匹配更多模式 三、常用字符分类的缩写代码 总结 所谓正则表达式&#xff08;regex&#xff09;&#xff0c;就是一种模式匹配&#xff0c;学会用正则匹配&#xff0c;就可以达到事半功倍的效果。 一、正则表达式在…

本地资源检测|单规则多阈值设置功能上线

作为一款可以全面自动检测项目静态工程内各项资源、代码和设置的UWA服务&#xff0c;本地资源检测能够帮助项目组制定合理的资源与代码标准&#xff0c;及时发现潜在的性能问题和异常错误&#xff0c;建立有效的开发规范意识。 此次3.1.0版本更新&#xff0c;在优化和完善现有…

Rcpp包运行C++代码

提高 R 脚本性能的最简单、最快捷的方法是更改脚本的问题部分并用 C 重写它们。Rcpp包提供了 R 和 C 之间的接口。1. cppFunction()转换简单的C函数### 1. cppFunction()转换简单的C函数 library(Rcpp) cppFunction(codeint fibonacci(const int x){if(x < 2) return x;if(x…

项目日记:学成在线(第二天P24~p34)

1、注入的两种方式&#xff1a;Autowired、Resource&#xff08;基于类型和名称&#xff09; 相同&#xff1a; Resource和Autowired都是做bean的注入时使用 不同&#xff1a; ①Autowird 属于spring框架,默认使用类型(byType)进行注入&#xff1a;&#xff08;基于类型&#x…

堆溢出——unlink漏洞攻击(bamboobox)

题目自取&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1S9xbAWhFw0xFqFyQTACqLA?pwdvvud 提取码&#xff1a;vvud 介绍&#xff1a; 终于学到Unlink了&#xff0c;不得不说和栈的难度相比确实大了很多&#xff0c;学起来确实很淦&#xff0c;一个unlink漏洞也确…

VSCode配置git bash为默认终端

打开左下角齿轮图标 打开Settings 搜索框输入 terminal.integrated.profiles.windows, 在下方显示的内容上点击 Edit in settings.json 配置修改如下 "terminal.integrated.profiles.windows": {"PowerShell": {"source": "PowerShell&qu…

Python每日一练(20230322)

目录 1. Excel表列序号 &#x1f31f; 2. 单词拆分 &#x1f31f;&#x1f31f; 3. 删除有序数组中的重复项 II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练…

营销即服务!怎么做小程序店铺打造优质用户体验?

随着移动互联网的快速发展&#xff0c;小程序已经成为了许多企业打造优质用户体验的重要工具。一个好的小程序店铺能够为用户提供良好的购物体验&#xff0c;提高用户满意度和转化率。那么&#xff0c;怎么做小程序店铺打造优质用户体验呢&#xff1f; 一&#xff1a;做小程序店…

Linux 信号(signal):信号的捕捉流程

目录一、程序的运行状态二、信号捕捉流程在处理信号的时候&#xff0c;其实要经过一系列流程的&#xff0c;本文就来简单介绍一下信号处理的捕捉流程。 一、程序的运行状态 程序运行状态分为内核态和用户态。程序在运行库函数、用户自定义函数等第三方函数时就会在用户态运行&…

VSCode for C/C++ 插件

VSCode for C/C 插件功能性插件C/C【千万级下载&#xff01;】必选C/C Extension Pack【千万级下载&#xff01;】扩展包Code Runner【千万级下载&#xff01;必备】右键代码运行&#xff0c;格式化在终端的显示CMake、 CMake Integration、CMake Language Support、CMake Tool…

达梦数据库普通表转分区表

在生产环境中&#xff0c;数据库中一开始用的是普通表&#xff0c;但随着时间推移&#xff0c;数据量越来越大&#xff0c;可以考虑将普通表转换为分区表&#xff0c;提升数据库的性能。本文将介绍在DM8数据库中&#xff0c;实现将普通表转换为分区表的方法。环境说明数据库版本…

SpringBoot基础教程

springboot基础 一、springboot介绍 Spring Boot 提供一种快速使用spring的方式&#xff0c;基于约定大于配置的思想&#xff0c;可以让开发者不必在配置与逻辑业务中来回进行思维切换&#xff0c;全身心的投入到业务的代码编写中&#xff0c;从而大大提高了开发效率。2014年…

TypeScript的枚举与类型约束

● 上一章我们讲了 TS 的接口 ● 这一章, 我们就来聊一聊 TS 的枚举和约束 枚举 认识枚举 ● 在很多计算机语言中都有枚举的概念, 但是 JS 中是没有枚举这个概念的, 为了弥补这个缺憾 在 TS 加入了枚举类型 ● 什么是枚举呢 ? 枚举( mei ju ) : 枚举的意思就是一一列举,…

PyTorch 深度学习实战 | 基于 ResNet 的花卉图片分类

“工欲善其事&#xff0c;必先利其器”。如果直接使用 Python 完成模型的构建、导出等工作&#xff0c;势必会耗费相当多的时间&#xff0c;而且大部分工作都是深度学习中共同拥有的部分&#xff0c;即重复工作。所以本案例为了快速实现效果&#xff0c;就直接使用将这些共有部…

【C++初阶】六、模板初阶(函数模板+类模板)

文章目录泛型编程函数模板函数模板的概念函数模板的格式函数模板的原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化泛型编程 引入 - 通用的交换函数 如果让你编写一个函数&#xff0c;用于两个数的交换。在C语言中&#xff0c;我们会用如下方法…

我让Chat GPT准备了几份SAP 顾问英文面试自我介绍的模板,大家感受一下

有个朋友说有个面试要用英文来做自我介绍&#xff0c;我灵机一动&#xff0c;不如让Chat GPT准备了几份SAP 顾问英文面试自我介绍的模板&#xff0c;大家感受一下。我看下来感觉写的还是中规中矩&#xff0c;可以一用&#xff0c;。 模板1 Sure, I can help you with that! Her…

【Java学习笔记】39.Java 多线程编程

Java 多线程编程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流&#xff0c;一个进程中可以并发多个线程&#xff0c;每条线程并行执行不同的任务。 多线程是多任务的一种特别的形式&#xff0c;但多线程使用了更小的资源开销。 这里定义和…