平衡二叉树(AVL)

(附代码,简洁好理解)

目录

什么是平衡二叉树?

如何保证二叉树平衡?

左旋/右旋

左右双旋/右左双旋

代码

树的结构:

 树的高度与平衡因子:

左/右旋: 

平衡维护: 

构建树: 


什么是平衡二叉树?

简单来说就是二叉搜索树的升级版。一般的二叉搜索树在建树时,可能会建成一个长长的链,比如依次插入key值:1,2,3,4,5。则建出来的二叉搜索树会是一条长链。这样不利于查找搜索。为了解决这个问题,我们可以将二叉搜索树尽量建得平衡一些,即限制二叉树与二叉树的所有子树的左右子树的高度差绝对值不能超过1。这样的树就是平衡二叉树。根结点的左右子树的高度差就称作平衡二叉树的平衡因子。即平衡因子=左子树高度-右子树高度。

如何保证二叉树平衡?

左旋/右旋

如果左子树高度-右子树高度>1,即平衡因子>1,那么该怎么办?

我们可以将树整体向右“旋转”,即右旋。也可以理解为把树的右半部分拉长,把左半部分上提。这样就能够使树更加趋近平衡状态。如果平衡因子<-1,也是同理,将树整体向左“旋转”,即左旋。也可以理解为把树的左半部分拉长,把右半部分上提。

具体操作就是:如果左子树高度-右子树高度>1,那么我们将左子树的根结点作为现在的根节点整体往上提。然后为了保证二叉搜索树依然有序,我们将原先的根结点变作现在的根结点的右子树根节点。原先的根节点的左子树变作原先的左子树的右子树。(可能有点绕,其实就是将树看作三部分:[原先根结点的左子树,原先的根结点,原先根结点的左子树的右子树],这样或许会好理解一点?)。

代码可能更加直观:

//右旋
void R(node* &root){node* temp=root->l;root->l=temp->r;temp->r=root;updateH(root);updateH(temp);root=temp;
}//左旋
void L(node* &root){node* temp=root->r;root->r=temp->l;temp->l=root;updateH(root);updateH(temp);root=temp;
}

可以这样想,既然左子树变作了根结点,那么我原先的根结点的左子树不就空出来了?但是不能让它空着,所以我们将选左子树的右子树作为原先的根节点的左子树(因为左子树上的结点包括他的右子树都要小于原先的根结点,所以这样换了之后能够依然有序)。那左子树变作了根节点,他的右子树又被原先的根结点抢走了,他现在的右子树岂不是也空出来了?没事,让原先的根结点作你的右子树呗。于是这样调整后二叉树依然有序,且平衡。

左右双旋/右左双旋

那么只需要这样左旋/右旋一次操作就能保持二叉树平衡嘛?

不一定,考虑一种情况,左子树高度-右子树高度>1,并且左子树的右子树高于左子树的左子树,那么我们进行一次右旋操作后是怎样的?我们会发现,由于左子树的右子树在进行右旋操作后变成了现在的右子树的左子树。深度不变,那么也就意味着现在的左右子树的高度差变成了原先的左子树的左右子树高度差+1(因为左子树高度提高了,所以+1)那么还不是高度差一样超过了1嘛。所以遇到这种情况,我们不能直接进行右旋,需要对左子树先进行一次左旋后,调整左子树的左右子树高度差,保证左子树的左子树高于或等于右子树,再对整体进行右旋。这样的操作就叫做左右双旋。反之,如果是左子树高度-右子树高度<-1,并且右子树的左子树高于右子树的右子树,那么我们就需要进行右左双旋操作。这个操作只需要在进行维护平衡时判定一下就行。

代码

看代码更加直观:

树的结构:

struct node{int val;int h;//多出一个高度属性node* l;node* r;node(int x):val(x),h(1),l(nullptr),r(nullptr){}
};

 树的高度与平衡因子:

//高度
int getH(node* root){if(root==nullptr)return 0;return root->h;
}
void updateH(node* root){root->h=max(getH(root->l),getH(root->r))+1;
}
//平衡因子
int getB(node* root){return getH(root->l)-getH(root-r);
}

左/右旋: 

//右旋
void R(node* &root){node* temp=root->l;root->l=temp->r;temp->r=root;updateH(root);updateH(temp);root=temp;
}//左旋
void L(node* &root){node* temp=root->r;root->r=temp->l;temp->l=root;updateH(root);updateH(temp);root=temp;
}

平衡维护: 

//维护树的平衡
void keepB(node*&root){if(getB(root)>1){if(getB(root->l)<0)L(root->l);//如果,,先进行左旋R(root);}else if(getB(root)<-1){if(getB(root->r)>0)R(root->r);//如果,,先进行右旋L(root);}
}

构建树: 

//插入结点
void insert(node* &nod,int val){if(nod==nullptr){nod=new node(val);return ;}if(val<nod->val){insert(nod->l,val);updateH(nod);keepB(nod);}else {insert(nod->r,val);updateH(nod);keepB(nod);}
}

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

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

相关文章

70-76-堆、贪心算法

LeetCode 热题 100 文章目录 LeetCode 热题 100堆70. 中等-数组中的第K个最大元素71. 中等-前K个高频元素72. 困难-数据流中的中位数 贪心算法73. 简单-买卖股票的最佳时机74. 中等-跳跃游戏75. 中等-跳跃游戏II76. 中等-划分字母区间 本文存储我刷题的笔记。 堆 70. 中等-数组…

数字图像处理Python实现-图像特效与卷积滤波

图像特效与卷积滤波 文章目录 图像特效与卷积滤波1、准备2、快速了解卷积滤波3、应用卷积滤波在这篇文章中,我们将探索如何使用卷积内核来实现图像的模糊、锐化、轮廓和浮雕等特效。 1、准备 像往常一样,我们导入 numpy 和 matplotlib 等库。 此外,我们从 skimage 和 scipy…

命令行编译java

十分惭愧&#xff0c;java学了有七八年了&#xff0c;现在才来写这个博客&#xff0c;但是相信正确的事情即使迟到也好过不到&#xff0c;希望借助博客可以帮助记忆。 单个java文件 这个相信大家都知道&#xff0c;只是为了结构明确。这里java会找到内部的main方法。必须是在…

跨境电商系统开发:开启全球贸易新纪元

随着全球电子商务的飞速发展&#xff0c;跨境电子商务已经成为了一种日益重要的贸易形式。跨境电商系统开发&#xff0c;为企业提供了全新的商业机遇&#xff0c;打开了全球贸易的新纪元。 跨境电商系统开发&#xff0c;旨在实现不同国家和地区之间的电子商务交易&#xff0c;促…

【机器学习】迁移学习

迁移学习&#xff1a;给定一个有标记的源域和一个无标记的目标域。这两个领域的数据分布不同。迁移学习的目的就是要借助源域的知识&#xff0c;来学习目标域的知识(标签)。或是指基于源域数据和目标域数据、源任务和目标任务之间的相似性&#xff0c;利用在源领域中学习到的知…

计算机毕业设计|基于SpringBoot+MyBatis框架的电脑商城的设计与实现(商品和购物车)

计算机毕业设计|基于SpringBootMyBatis框架的电脑商城的设计与实现&#xff08;商品和购物车&#xff09; 商品热销排行 1 商品-创建数据表 1.使用use命令先选中store数据库。 USE store;2.在store数据库中创建t_product数据表。 CREATE TABLE t_product (id int(20) NOT …

Git开发实用技巧

文章目录 一图胜千言&#xff1a;

SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测

SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测 目录 SCI一区级 | Matlab实现GWO-CNN-LSTM-selfAttention多变量多步时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现GWO-CNN-LSTM-selfAttention灰狼算法优化卷积长短…

中国加氢催化剂行业研究与投资前景报告(2023版)

内容简介&#xff1a; 炼油厂催化剂市场因类型、材料和地区而分散。不同的产品类型包括流化催化裂化&#xff08;FCC)、烷基化、重整和异构化、加氢处理等。基于材料&#xff0c;产品分为沸石、金属、化合物等催化剂。钼、钒、镍、钴和其他贵金属和稀土金属属于用于金属基炼油…

介绍比特币上的 sCrypt 开发平台

最强大的基础设施和工具套件&#xff0c;可轻松构建和扩展您的 dApp 杀手级应用在哪里&#xff1f; 尽管比特币在小额支付、国际汇款和供应链管理等广泛用例中具有颠覆性潜力&#xff0c;但在推出 14 年后&#xff0c;我们还没有看到一款非常受欢迎并被主流采用的杀手级应用。 …

Java 从丑陋的典例代码来谈谈卫语句(guard statement)if else

最近在重构些老项目&#xff0c;发现了些比较典型的代码块。 想到这些常见的写法&#xff0c;可能初学者还是比较容易‘产出’的&#xff0c;所以决定拎出来说说。 实例&#xff1a; 可以看到&#xff0c;这是一个用于新增&修改前的一个名称检测是否重复的函数。 /*** 检测…

echart一键生成迁徙图

echart_move 介绍 echart迁徙图&#xff0c;选择起点和目的地生成迁徙图 软件架构 html echarts js 使用说明 将文件放到同一目录下打开index.html即可 默认是小飞机图标&#xff0c;如果想修改图标&#xff0c;将图片放到同一目录&#xff0c;如1.svg 代码修改为对应位…

这一次,Python 真的有望告别 GIL 锁了?

Python 中有一把著名的锁——全局解释器锁&#xff08;Global Interpreter Lock&#xff0c;简写 GIL&#xff09;&#xff0c;它的作用是防止多个本地线程同时执行 Python 字节码&#xff0c;这会导致 Python 无法实现真正的多线程执行。&#xff08;注&#xff1a;本文中 Pyt…

Controller 层代码就该这么写,简洁又优雅!

一个优秀的 Controller 层逻辑 说到 Controller&#xff0c;相信大家都不陌生&#xff0c;它可以很方便地对外提供数据接口。它的定位&#xff0c;我认为是「不可或缺的配角」。 说它不可或缺是因为无论是传统的三层架构还是现在的 COLA 架构&#xff0c;Controller 层依旧有…

DEM分析

一、实验名称&#xff1a; DEM分析 二、实验目的&#xff1a; 通过本实验练习&#xff0c;掌握DEM的建立与应用基本方法。 三、实验内容和要求&#xff1a; 实验内容&#xff1a; 利用ARCGIS软件相关分析工具及实验数据&#xff0c;创建DEM&#xff0c;并计算相应坡度的区…

webshell之编码免杀

Unicode编码 jsp支持unicode编码&#xff0c;如果杀软不支持unicode查杀的话&#xff0c;基本上都能绕过 注意这里的\uuuu00可以换成\uuuu00uuu...可以跟多个u达到绕过的效果 将代码&#xff08;除page以及标签&#xff09;进行unicode编码&#xff0c;并条件到<%%>标签…

sCrypt 在英国伦敦 Exeter 大学讲学

6月5日&#xff0c;sCrypt CEO晓晖和他的两位同事在英国伦敦Exeter大学举行了一场精彩的讲座。刘晓晖向听众们详细介绍了sCrypt智能合约开平台&#xff0c;并演示了如何使用sCrypt来开发基于比特币的智能合约。他用生动形象的语言&#xff0c;深入浅出地解释了这个领域复杂而又…

16、单例bean的优势

一、单例bean的优势 由于不会每次都新创建新对象所以有一下几个性能上的优势&#xff1a; 减少了新生成实例的消耗。新生成实例消耗包括两方面&#xff0c;第一&#xff0c;spring会通过反射或者cglib来生成bean实例&#xff0c;这都是耗性能的操作&#xff0c;其次给对象分配…

精通Nginx(18)-FastCGI/SCGI/uWSGI支持

最初用浏览器浏览的网页只能是静态html页面。随着社会发展,动态获取数据、操作数据需要变得日益强烈,CGI应运而生。CGI(Common Gateway Interface)公共网关接口,是外部扩展应用程序与静态Web服务器交互的一个标准接口。它可以使外部程序处理浏览器送来的表单数据并对此作出…

24. 深度学习进阶 - 矩阵运算的维度和激活函数

Hi&#xff0c;你好。我是茶桁。 咱们经过前一轮的学习&#xff0c;已经完成了一个小型的神经网络框架。但是这也只是个开始而已&#xff0c;在之后的课程中&#xff0c;针对深度学习我们需要进阶学习。 我们要学到超参数&#xff0c;优化器&#xff0c;卷积神经网络等等。看…