(AVL)平衡二叉树

news/2024/5/18 14:33:36/文章来源:https://blog.csdn.net/weixin_51609435/article/details/128028751

还是照旧,本篇主要讲一下代码实现,AVL相关的定义什么的这里不多赘述。

AVL树就是为了解决bst树出现了“线性”的问题,而发明的。什么是线性的就是一棵bst树全都只有左子树或者全都只有右子树,能想象来吧。

目录

 LL型调整(左旋)

RR型调整(右旋)

LR调整

RL调整

 代码实现:


因此呢AVL树一定是一棵bst树。不了解bst的可以先看看我这篇文章:(BST) 二叉排序树

AVL树是一类特殊的二叉排序树,它或者为空树,或者其左右子树都是平衡二叉排序树,而且其左右的子数高度之差绝对值不超过1.为了保证相对平衡,每次插入元素都会做相应的旋转

上面说了为了让avl树能保持平衡,每次插入节点后不平衡了就需要调整,旋转。

 这样的话就衍生出来了avl的四种旋转方式,四种旋转方式搞懂了,avl的创建就没问题了 

下面说说四种调整方式

 LL型调整(左旋)

A的左孩子的左孩子插入新的节点,导致A的平衡因子从1变为2,不在满足根本性质[-1,1],所以需要通过旋转。显然,按照大小关系,结点B应作为新的根结点,其余两个节点分别作为左右孩子节点才能平衡,这样看来,仿佛A结点绕结点B顺时针旋转一样。

当在节点5的左子树中插入节点的时候而导致不平衡。这种情况调整如下:首先将元素5的左孩子2提升为新的根结点;然后将原来的根结点元素5变为元素2的右孩子;其他各子树按大小关系连接。

RR型调整(右旋)

在元素5的右孩子的右孩子插入新的节点,导致元素5的平衡因子从-1变为-2,不在满足根本性质[-1,1],所以需要通过旋转。显然,按照大小关系,结点元素7应作为新的根结点,其余两个节点分别作为左右孩子节点才能平衡,这样看来,仿佛节点元素5绕结点元素7逆时针旋转一样。

LR调整

节点元素5的左孩子的右子树上插入新节点,导致不平衡。此时元素5的平衡因子由1变为2。第一张图是LR型的最简单形式。显然,按照大小关系,元素3应作为新的根结点,其余两个节点分别作为左右孩子节点才能平衡。

节点元素6增加一个左孩子,导致元素4变得不平衡。先顺时针旋转元素7再逆时针旋转4元素达到平衡。 

RL调整

当在元素5的右孩子的左子树增加一个节点7的时候,会造成不平衡的情况。先逆时针旋转成RR情况,再将元素5顺时针旋转。

 第二种情况方法类似,看起来会复杂一点。当在元素7得左孩子6增加左孩子元素5得时候,导致元素4变得不平衡。那么先顺时针调整元素7,再逆时针调整元素4

 代码实现:

主类大概这样:

class AVLNode {
public:AVLNode():m_left(nullptr),m_right(nullptr),m_bf(0){}AVLNode(int v):m_value(v), m_left(nullptr), m_right(nullptr), m_bf(0) {}int m_value;AVLNode *m_left;AVLNode *m_right;int m_bf;//平衡因子,该结点左右子树高度(深度)差
};
class AVLTree {
public:AVLTree() :m_root(nullptr){}void InsertAVLTree(int v) {InsertAVLTree(m_root, v);}//传指针 再引用直接就在原来的树上修改了//斜线       void RotateRR(AVLNode*& t);//右旋void RotateLL(AVLNode*& t);//左旋//折线void RotateRL(AVLNode*& t);//右左旋void RotateLR(AVLNode*& t);//左右旋void InsertAVLTree(AVLNode* &t, int v);//插入void DelAVLTree(int key);//删除当前key这个值void TTer(AVLNode*& t);//中序遍历AVLNode* m_root;
};

四个调整函数:

void AVLTree::RotateLL(AVLNode*& t)
{AVLNode* child = t;t = child->m_right;child->m_right = t->m_left;t->m_left = child;t->m_bf = child->m_bf = 0;
}
void AVLTree::RotateRR(AVLNode*& t)
{AVLNode* child = t;t = child->m_left;child->m_left = t->m_right;t->m_right = child;t->m_bf = child->m_bf = 0;
}
void AVLTree::RotateRL(AVLNode*& t)
{AVLNode* childL = t;AVLNode* childR = t->m_right;t = childR->m_left;//先右旋//将t的右孩子作为childR的左孩子,childR作为t的右孩子childR->m_left = t->m_right;t->m_right = childR;if (t->m_bf >= 0) {childR->m_bf = 0;}else {childR->m_bf = 1;}//再左旋childL->m_right = t->m_left;//左子树t->m_left = childL;if (t->m_bf==1) {childL->m_bf = -1;}else {childL->m_bf = 0;}t->m_bf = 0;
}
void AVLTree::RotateLR(AVLNode*& t)
{AVLNode* childR = t;AVLNode* childL = t->m_left;t = childL->m_right;//先左旋childL->m_right = t->m_left;//左子树t->m_left = childL;if (t->m_bf <= 0){childL->m_bf = 0;}else{childL->m_bf = -1;}//再右旋childR->m_left = t->m_right;//右子树t->m_right = childR;if (t->m_bf ==-1){childR->m_bf = 1;}else{childR->m_bf = 0;}t->m_bf = 0;
}

AVL的插入创建

void AVLTree::InsertAVLTree(AVLNode*& t, int v)
{AVLNode* p = t;AVLNode* parent = nullptr;stack<AVLNode*>sk;//存储路径上的所有节点while (p != nullptr) {if (p->m_value == v) {return;}parent = p;sk.push(parent);//入栈为计算插入新节点后路径上父辈的bfif (v < p->m_value){p = p->m_left;}else{p = p->m_right;}}//用v生成新节点p = new AVLNode(v);if (parent == nullptr){t = p;return;}//将p链接到树中对应的位置if (v < parent->m_value) {parent->m_left = p;}else {parent->m_right = p;}//计算bfwhile (!sk.empty()){parent = sk.top();sk.pop();//这里我们用右边减左边来算if (parent->m_left == p)//如果此时p插到了parent的左边{parent->m_bf--;}else{parent->m_bf++;}if (parent->m_bf == 0)//一定平衡着,高度没有发生变化{/*  bf-1     30   2插入个4变成了0     30   2   4*/break;}if (abs(parent->m_bf) == 1){//如果插入后bf绝对值等于1//那么有可能不平衡,需要往上看p = parent;}else{//父结点的bf绝对值为2,此时作为最小不平衡子树,开始旋转int flag = parent->m_bf > 0 ? 1 : -1;if (p->m_bf == flag)//斜线,同号{if (flag == -1)//右旋	RotateRR(parent);else//左旋		RotateLL(parent);}else {//折线,不同号if (flag == 1)//右高,先右旋再左旋{RotateRL(parent);}else{//先左旋再右旋RotateLR(parent);}}	break;}}//旋转后需要进行调整,if (sk.empty())//此时栈空了说明不用链接了{t = parent;}else{AVLNode* q = sk.top();if (q->m_value > parent->m_value)//栈顶大于parent,往左链接{q->m_left = parent;}else{q->m_right = parent;}}
}

AVL删除特定值节点

void AVLTree::DelAVLTree(int k)//删除当前key这个值
{AVLNode* p = m_root;AVLNode* parent = NULL, * ppr = NULL;stack<AVLNode*> st;while (p){if (p->m_value == k)break;parent = p;st.push(parent);if (k < p->m_value)p = p->m_left;elsep = p->m_right;}if (p == NULL)return;AVLNode* q = NULL;if (p->m_left != NULL && p->m_right != NULL){parent = p;st.push(parent);q = p->m_left;while (q->m_right != NULL){parent = q;st.push(parent);q = q->m_right;}//替换p->m_value = q->m_value;p = q;}if (p->m_left != NULL)q = p->m_left;elseq = p->m_right;int f; //标记删除的是左孩子0,右孩子1if (parent == NULL)m_root = parent;else{if (parent->m_left == p){parent->m_left = q;f = 0;}else{parent->m_right = q;f = 1;}//删除完后调整bf//根据栈中存储的路径计算bfint link;while (!st.empty()){parent = st.top();st.pop();if (parent->m_right == q && f == 1)parent->m_bf--;elseparent->m_bf++;if (!st.empty()){//保存旋转之前的父节点,为了旋转后链接ppr = st.top();link = (ppr->m_left == parent) ? -1 : 1;}elselink = 0;if (parent->m_bf == -1 || parent->m_bf == 1)break;if (parent->m_bf == 0)q = parent;else{//旋转int flag = 0;if (parent->m_bf < 0){flag = -1;q = parent->m_left;}else{flag = 1;q = parent->m_right;}if (q->m_bf == 0)//单{if (flag == -1)//左高{RotateRR(parent);parent->m_bf = 1;parent->m_right->m_bf = -1;}else{RotateLL(parent);parent->m_bf = -1;parent->m_left->m_bf = 1;}break;}if (q->m_bf == flag){if (flag == -1)RotateRR(parent);elseRotateLL(parent);}else{if (flag == -1)RotateLR(parent);elseRotateRL(parent);}if (link == -1)ppr->m_left = parent;else if (link == 1)ppr->m_right = parent;}}if (st.empty())m_root = parent;}delete p;p = NULL;
}

写个简单的中序遍历,用来打印测试一下,因为bst树中序是从小到大排序的,那avl中序必然也是有序的

void AVLTree::TTer(AVLNode*& cur) {if (cur == nullptr)return;TTer(cur->m_left);cout << cur->m_value << " " ;TTer(cur->m_right);
}

写个测试:

int  main()
{vector<int>nums{ 3,2,1,4,5,6,7,10,9,8 };AVLTree t;for (const auto& x : nums){t.InsertAVLTree(x);//插入}t.TTer(t.m_root);//写个中序 遍历出来从小到大t.DelAVLTree(5);//删除个5cout << endl;t.TTer(t.m_root);return 0;
}

ok完事收工

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

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

相关文章

axios.defaults.baseURL的三种配置方法

axios.defaults.baseURL的三种配置方法目录概述需求&#xff1a;设计思路实现思路分析1.少2.2.动态获取请求地址3.3.采用配置文件参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,m…

Spring学习:二、Bean的管理

4. Bean的管理 ​ Spring的基本Bean管理包括Bean配置&#xff0c;Bean实例化和Bean的依赖注入。这些管理可以通过手工编码的方式把每个Bean注册到容器中&#xff0c;也可以通过properties文件和xml文件配置Bean和Bean之间的依赖关系。通常我们的配置方式是XML作为配置文件。 …

DNS查询流程

&#x1f468;‍&#x1f4bb;个人主页&#xff1a; 才疏学浅的木子 &#x1f647;‍♂️ 本人也在学习阶段如若发现问题&#xff0c;请告知非常感谢 &#x1f647;‍♂️ &#x1f4d2; 本文来自专栏&#xff1a; 计算机网络 ❤️ 支持我&#xff1a;&#x1f44d;点赞 &#…

李宏毅《DLHLP》学习笔记6 - 语言模型

视频链接&#xff1a;https://www.youtube.com/watch?vdymfkWtVUdo&listPLJV_el3uVTsO07RpBYFsXg-bN5Lu0nhdG&index8&ab_channelHung-yiLee 课件链接&#xff1a;https://speech.ee.ntu.edu.tw/~tlkagk/courses/DLHLP20/ASR3.pdf 1. Language Model LM的作用是预…

FFmpeg二次开发

本文主要讲解 FFmpeg 的二次开发&#xff0c;ffmpeg.exe 的命令行功能特别强大&#xff0c;很多需求都能直接用命令行实现&#xff0c;但是总有一些需求用 命令行实现不太好做。 而你实现那些特殊需求&#xff0c;通常需要把 ffmpeg.exe 里面的某部分代码抄过来&#xff0c;本…

阿里云新用户活动:云服务器ECS 新购、升级报价出炉了!

阿里云新人特惠&#xff0c;阿里云新用户新购升级立享满减&#xff0c;新购升级云服务器ECS &#xff0c;购买热门产品 s6/u1/c6/g6/r6/c7/g7/r7指定配置&#xff0c;可享折上折&#xff01;从未购买过云服务器ECS或者轻量应用服务器的用户一次性可领取3张优惠券。优惠券适用于…

VS Code快速实现Git PR操作

注意&#xff1a;建议先学习git的基本操作。 安装插件 下图中红圈标记的插件都安装好。 Fork上游仓库 在网页上点击你想要fork的仓库&#xff0c;点击fork 然后该仓库就会fork到你的github账户下面&#xff0c;如下图。 现在可以在你账户下面的repo&#xff08;我们称为下…

Allegro如何移动器件操作指导

Allegro如何移动器件操作指导 Allegro上可以任意移动器件,具体操作如下 选择Edit-move Find选择Symbols Point根据需要选择 Sym Origin是抓取器件的原点 Body center是抓取器件的中心 User Pick可以自定义抓取的原点,在移动整个模块的并且旋转的时候常用的命令 Sym Pin#设…

【抓包工具】win 10 / win 11:WireShark 下载、安装、使用

目录 一、WireShark 下载 二、WireShark 安装 &#xff08;1&#xff09;双击运行安装程序 &#xff08;2&#xff09;Choose Components&#xff1a;选择组件 &#xff08;3&#xff09;Additional Tasks&#xff1a;附加任务 &#xff08;4&#xff09;Choose lnstall …

Pikachu靶场全关攻略(超详细!)

一、靶场搭建 准备工具 phpstudy**pikachu靶场下载地址&#xff1a;**https://github.com/zhuifengshaonianhanlu/pikachu 搭建过程 将靶场文件夹放到phpstudy的www目录 进入pikach文件夹的inc目录&#xff0c;修改靶场配置文件config.inc.php&#xff0c;设置数据库账号密…

微服务框架 SpringCloud微服务架构 10 使用Docker 10.6 容器命令练习

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构10 使用Docker10.6 容器命令练习10.6.1 直接开干10 使用Docker 10.6 容器…

Stable Diffusion 2.0 来了

Stable Diffusion 一经发布&#xff0c;就立刻在业界掀起巨大的波浪。我个人后知后觉&#xff0c;直到 Stable Diffusion V1.4 版本发布&#xff0c;才接触 Stable Diffusion (之前使用的是 Disco Diffusion)。这段时间&#xff0c;SD 团队也没闲着&#xff0c;很快就发布了 V2…

HTML学生个人网站作业设计 明星易烊千玺介绍(HTML+CSS) web前端开发技术 web课程设计 网页规划与设计

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

2022年第十一届认证杯数学中国数学建模国际赛小美赛:C 题 对人类活动进行分类 建模方案及代码实现

2022年第十一届认证杯数学中国数学建模国际赛小美赛&#xff1a;C 题 对人类活动进行分类 建模方案及代码实现 1 题目 人类行为理解的一个重要方面是对日常活动的识别和监控。可穿戴活动识别系统可以在许多关键领域提高生活质量&#xff0c;如门诊监测、居家康复、跌倒检测等。…

[附源码]计算机毕业设计springboot校园代取快递系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

GameOff2022参与有感

GameOff2022参与有感以及年度总结 厚颜无耻的用我们美术的立绘 GameOff— Redemption 很高兴在一个月的时间里面和大家一起完成了《Redemption》 比赛链接&#xff1a;Itch.io 百度云盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ylK0QRr2lmkqi4JF1wsXtA 提…

[附源码]计算机毕业设计springboot疫情管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

天宇优配|研判明年下半年投资机会或更大 险资看好“安全”与“发展”

上海证券报记者昨日获悉&#xff0c;多家稳妥资管公司已经拟定2023年出资战略&#xff0c;跟着本年以来多项稳经济方针逐步落地&#xff0c;险资遍及看好下一年经济复苏带来的商场出资时机。 权益出资方面&#xff0c;险资以为&#xff0c;当时股票商场估值处于前史较低水平&am…

重点问题!CPU利用率过高排查思路|原创

本文讲解了重点面试问题CPU利用率高如何排查和解决。点击上方“后端开发技术”&#xff0c;选择“设为星标” &#xff0c;优质资源及时送达CPU利用率高怎么办&#xff1f;如何排查和解决这是一个常见的面试问题&#xff0c;也是线上常遇到的问题之一。遇到线上服务器异常告警&…

Maven的简单介绍

Maven 构件 <packaging> : pom、jar、ear、war以及maven-plugin,构建Maven之后所生成的文件类型&#xff0c;Pom本身不产生构件&#xff0c;用来作为依赖库。 pom类型常用于微服务中作为父Pom,通过 可以将子模块包含进来&#xff0c;共享父Pom的依赖&#xff0c; GAV坐标…