AVL树的底层实现

文章目录

  • 什么是AVL树?
  • 平衡因子
  • Node节点
  • 插入
    • 新节点插入较高左子树的左侧
    • 新节点插入较高左子树的右侧
    • 新节点插入较高右子树的左侧
    • 新节点插入较高右子树的右侧
  • 验证是否为平衡树
  • 二叉树的高度
  • AVL的性能

什么是AVL树?

AVL树又称平衡二叉搜索树,相比与二叉搜索树多了平衡的概念,为什么要有平衡二叉搜索树呢?因为二叉搜索树可能会出现退化现象,导致左右子树高度相差较大,甚至退化成单链表的形式,因此我们提出了平衡二叉搜索树,可以有效地解决高度相差过大的情况,平衡二叉搜索树要求任意节点的左右子树高度相差不大于1.

平衡因子

为了解决高度差问题,我们在每一个节点中添加了平衡因子变量,这个变量用于记录该节点的左右子树的高度差。
若规定平衡因子等于右子树高度减去左子树高度,那么如果新增节点的位于当前节点的左侧那么该节点平衡因子-1,如果位于该节点的右侧,则该节点平衡因子+1,并且一直向上修改平衡因子,直到某个节点平衡因子为0,或者到根节点,或者需要进行调整

Node节点

template <class K, class V>
struct AVLTreeNode
{pair<K, V> _kv;//pair是库中的类,包含first和second两个成员变量AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf;//blance factorAVLTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};

我们规定平衡因子等于右子树高度减去左子树高度

插入

平衡二叉搜索树也是二叉搜索树,因此它的插入和二叉搜索树类似,都是找到一个合适的节点进行插入,不同的是这棵树要保证每个节点的平衡因子不大于1,因此我们在插入后可能需要对该树的节点进行调整。
需要调整的情况有以下四种:分别是

新节点插入较高左子树的左侧

情况1:
在这里插入图片描述

情况2
在这里插入图片描述

上面两种情况的处理方式是一样的,因为这两种情况都属于较高子树的左边,以图为例,5和10所在位置分别是不平衡节点9的左右子树,而新插入的节点都是位于左子树的根节点5的左侧

思路:如果新插入的节点位于不平衡节点的左子树的左侧,要想让不平衡节点变平衡,就要让高的一侧子树高度-1,低的一侧子树高度+1,这样就可以使得原本高度差为2的左右子树的高度差变为0,同时还要保证二叉树的性质不被破坏,所以还要对6进行处理。
右单旋:不平衡节点以及它的右子树进行,绕不平衡节点的左孩子旋转90度。
右单旋是指不平衡节点以及它的右子树进行旋转

//新节点插入较高左子树的左侧----左左: 右单旋
void RotateR(Node* parent)
{++_rotateCount;Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;/if (curright){//parent->_right = curright;curright->_parent = parent;}cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;//if (parent = _root)if(ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (parent == ppnode->_left){//cur = ppnode->_left;ppnode->_left = cur;}else{//cur = ppnode->_right;ppnode->_right = cur;}cur->_parent = ppnode;}cur->_bf = parent->_bf = 0;
}

最后不要忘记把新插入节点和那个不满足平衡因子的左孩子的平衡因子都置为0

新节点插入较高左子树的右侧

在这里插入图片描述
新插入节点位于7的左右两侧都属于同一种情况,这里就不做演示了。
先把不满足平衡因子的节点的左孩子进行左旋转,在对不满足平衡因子的节点进行右旋转。

//新节点插入较高左子树的右侧---左右:先左单旋再右单旋
void RotateLR(Node* parent)//先左旋再右旋
{Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){parent->_bf = 0;cur->_bf = 0;curright->_bf = 0;}else if (bf == 1){curright->_bf = 0;cur->_bf = -1;parent->_bf = 0;}else if (bf == -1){curright->_bf = 0;cur->_bf = 0;parent->_bf = 1;}else{assert(false);}
}

调整完之后不要忘记对旋转节点的平衡因子进行调整

新节点插入较高右子树的左侧

插入到较高右子树左侧与插入到较高左子树右侧对称,因此调整方式恰好相反,因此是先右旋再左旋

//新节点插入较高右子树的左侧---右左:先右单旋再左单旋
void RotateRL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
int bf = curleft->_bf;RotateR(parent->_right);
RotateL(parent);if (bf == 0)
{parent->_bf = 0;cur->_bf = 0;curleft->_bf = 0;
}
else if (bf == 1)
{curleft->_bf = 0;cur->_bf = 0;parent->_bf = -1;}
else if (bf == -1)
{curleft->_bf = 0;cur->_bf = 1;parent->_bf = 0;
}
else
{assert(false);
}
}

新节点插入较高右子树的右侧

左单旋是指不平衡节点以及它的左子树进行旋转
同理,与插入到较高左子树的左侧对称,因此是左单旋

//新节点插入较高右子树的右侧----右右:左单旋
void RotateL(Node* parent)
{++_rotateCount;Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;/if (curleft){//parent->_right = curleft;curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (parent == _root){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}cur->_bf = parent->_bf = 0;
}

验证是否为平衡树

bool IsBlance()
{return IsBlance(_root);
}bool IsBlance(Node* root)
{if (root == nullptr){return true;}int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << "平衡因子异常:" << root->_kv.first << " " << root->_bf << endl;return false;}return abs(rightHeight - leftHeight) < 2&& IsBlance(root->_right)&& IsBlance(root->_left);
}

二叉树的高度

int Height()
{return Height(_root);
}int Height(Node* root)
{if (root == nullptr){return 0;}int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

AVL的性能

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

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

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

相关文章

VSCode 运行java程序中文乱码

现象描述 java文件中包含中文&#xff0c;运行java程序后&#xff0c;乱码报错。 解决方法 原本运行指令为 cd "d:\programProjects\Java_proj\" ; if ($?) { javac Solution.java } ; if ($?) { java Solution } 需要添加 编码格式 -encoding utf8 cd &quo…

AI中文版怎么用,版本分享,GPT官网入口

网页版上线啦&#xff0c;在线助力大学生、上班族的高效生活&#xff01; GPT4.0是OpenAI最新推出的聊天模型&#xff0c;它的语言理解和生成能力比以前的版本更强大。对于忙碌的上班族来说&#xff0c;GPT4.0能帮助你高效处理工作中的大部分写作任务&#xff0c;比如撰写报告…

ROS服务(Service)通信:通信模型、Hello World与拓展

服务通讯是基于请求响应模式的&#xff0c;是一种应答机制。 用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输场景。 一、服务通讯模型 服务是一种双向通讯方式&#xff0c;它通过请求和应答的方式传递消息&#xff0c;该模型涉及到三个角色&#xff1a; Master…

ubuntu云服务器配置SFTP服务

目录 一、安装并运行SSH服务 1&#xff0c;安装ssh服务 2&#xff0c;运行ssh 3&#xff0c;查看ssh运行状态 二、创建SFTP用户并进行用户相关的配置 1&#xff0c;创建SFTP用户 2&#xff0c;限制用户只能使用 SFTP&#xff0c;并禁止 SSH 登录。打开/ect/ssh/sshd_conf…

【源码系列】短剧系统开发国际版短剧系统软件平台介绍

系统介绍 短剧是一种快节奏、紧凑、有趣的戏剧形式&#xff0c;通过短时间的精彩表演&#xff0c;向观众传递故事的情感和思考。它以其独特的形式和魅力&#xff0c;吸引着观众的关注&#xff0c;成为了当代戏剧娱乐中不可或缺的一部分。短剧每一集都是一个小故事&#xff0c;…

ArcGIS创建格网

目录 1、创建网格 2、裁剪边界外的网格 3、只保留边界内完整的网格 1、创建网格 首先&#xff0c;我们在创建渔网前&#xff0c;需要指定渔网覆盖的范围。这里我们就以四子王为例 在ArcMap软件中&#xff0c;我们依次选择“Toolboxes”→“Data Management Tools&#xff0…

Centos上删除文件及目录的命令积累

01-如果我想删除Centos上当前目录下的文件 test06-2023-11-14-01.sql 该怎么操作&#xff1f; 答&#xff1a;如果你想删除CentOS上当前目录下的文件 test06-2023-11-14-01.sql&#xff0c;可以使用 rm 命令。以下是删除文件的基本语法&#xff1a; rm test06-2023-11-14-01.s…

结构体数组保存进二进制文件的简单做法

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 最近面临这样一个需求&#xff1a;以比较节省存储空间的存储一组坐标点到文件&#xff0c;要求程序能够跨平台读写这种文件。思考了一下&#xff0c;比较…

为开发GPT-5,OpenAI向微软寻求新融资

11月14日&#xff0c;金融时报消息&#xff0c;OpenAI正在向微软寻求新一轮融资&#xff0c;用于开发超级智能向AGI&#xff08;通用人工智能&#xff09;迈进&#xff0c;包括最新模型GPT-5。 最近&#xff0c;OpenAI召开了首届开发者大会&#xff0c;推出了GPT-4 Turbo、自定…

视频一键转码:批量转换MP4视频的技巧

随着数字媒体设备的普及&#xff0c;视频文件在生活中扮演着越来越重要的角色。而在处理视频文件时&#xff0c;有时需要将其转换为不同的格式以适应不同的需求。其中&#xff0c;MP4格式因其通用性和高质量而备受青睐。本文详解云炫AI智剪如何一键转码的技巧&#xff0c;帮助批…

基于SpringBoot的SSMP整合案例(在Linux中发布项目的注意事项与具体步骤步骤)

前言与注意 这几天在Linux中上线之前的小项目时&#xff0c;遇到了很多的问题&#xff0c;Linux镜像的选择&#xff0c;jdk&#xff0c; mysql在linux中的下载&#xff0c;使用finallshell连接linux&#xff0c;使用tomcat连接linux中的数据库........ 在下面的注意事项中我会将…

wpf devexpress 自定义统计

总计统计和分组统计包含预定义总计函数。这些函数允许你计算如下&#xff1a; 数据列的数量&#xff08;Count&#xff09; 最大和最小值(Max和Min) 总计和平均值&#xff08;Sum和Average&#xff09; 处理GridControl.CustomSummary 事件或者使用 GridControl.CustomSumm…

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边,Kotlin

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边&#xff0c;Kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.…

7、使用真机调试鸿蒙项目

此处以华为手机为例&#xff0c;版本为鸿蒙4.0. 一、打开手机调试功能 1、打开开发者模式 打开“设置”—“关于手机”&#xff0c;连续点击“软件版本”可打开开发者模式 2、开启USB调试功能 打开“设置”—“系统更新”—“开发者选项”&#xff0c;下拉找到“USB调试”…

ffmpeg5及以上-s和像素格式转换 画屏问题

环境: lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.10 Release: 22.10 Codename: kinetic拉下ffmpeg源码&#xff0c;6.0.1&#xff0c;4.3.6&#xff0c;5.1.4&#xff0c;依次安装作实验 ./configure --disable-x86asm …

【Linux】第十八站:进程等待

文章目录 一、进程等待的必要性1.进程等待是什么2.进程等待的必要性3.为什么要进程等待呢&#xff1f; 二、进程等待的方法1.问题2.wait3.waitpid4.status的原理5.等待失败6.与status有关的两个宏7.options 一、进程等待的必要性 1.进程等待是什么 通过系统调用wait/waitpid&a…

034、test

之——全纪录 目录 之——全纪录 杂谈 正文 1.下载处理数据 2.数据集概览 3.构建自定义dataset 4.初始化网络 5.训练 杂谈 综合方法试一下。 leaves 1.下载处理数据 从官网下载数据集&#xff1a;Classify Leaves | Kaggle 解压后有一个图片集&#xff0c;一个提交示…

Linux :远程访问的 16 个最佳工具(一)

通过远程桌面协议 (RDP) 可以访问远程 Linux 桌面计算机&#xff0c;这是 Microsoft 开发的专有协议。它为用户提供了一个图形界面&#xff0c;可以通过网络连接连接到另一台/远程计算机。 FreeRDP 是 RDP 的免费实现。 RDP以客户端/服务器模型工作&#xff0c;其中远程计算机必…

服务器集群配置LDAP统一认证高可用集群(配置tsl安全链接)-centos9stream-openldap2.6.2

写在前面 因之前集群为centos6&#xff0c;已经很久没升级了&#xff0c;所以这次配置统一用户认证也是伴随系统升级到centos9时一起做的配套升级。新版的openldap配置大致与老版本比较相似&#xff0c;但有些地方配置还是有变化&#xff0c;另外&#xff0c;铺天盖地的帮助文…

R语言绘制精美图形 | 火山图 | 学习笔记

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 教程图形 前言 最近的事情较多&#xff0c;教程更新实在是跟不上&#xff0c;主要原因是自己没有太多时间来学习和整理相关的内容。一般在下半年基本都是非常忙&#xff0c;所有一个人的精力和时间有限&#x…