图解平衡二叉搜索树

news2024/12/27 13:54:22

gitee仓库:https://gitee.com/WangZihao64/data-structure-and-algorithm/tree/master/avl

有如下一棵树(采用加入左结点平衡因子-1,加入右结点平衡因子+1的方式):

在这里插入图片描述

插入有以下几种情况:

1.平衡因子变为2

在这里插入图片描述

2.平衡因子变为0

在这里插入图片描述

3.平衡因子需要向上延伸(最多可延伸至父结点)

在这里插入图片描述

插入和二叉搜索树一样,平衡因子的更新规律如上图

bool Insert(const pair<K,V>& kv)
    {
        if(_root== nullptr)
        {
            _root=new Node(kv);
            return true;
        }
        Node* cur=_root;
        Node* parent=nullptr;
        while(cur)
        {
            if(cur->_kv.first>kv.first)
            {
                parent=cur;
                cur=cur->left;
            }
            else if(cur->_kv.first<kv.first)
            {
                parent=cur;
                cur=cur->right;
            }
            //遇到相同的值,返回false
            else
            {
                return false;
            }
        }
        cur=new Node(kv);
        if(kv.first>parent->_kv.first)
        {
            parent->right=cur;
            cur->parent=parent;
        }
        else
        {
            parent->left=cur;
            cur->parent=parent;
        }
        //parent最多可以走到根节点
        while(parent)
        {
            //parent的左孩子,_bf-1
            //否则_bf+1
            if(parent->left==cur)
            {
                --parent->_bf;
            }
            else if(parent->right==cur)
            {
                ++parent->_bf;
            }
            //parent如果是0,表明是平衡的,不需要做任何操作,直接退出
            if(parent->_bf==0)
            {
                break;
            }
            else if(parent->_bf==-1||parent->_bf==1)
            {
                //如果不平衡,也会影响到父节点的_bf
                cur=parent;
                parent=parent->parent;
            }
            //如果是2/-2就需要特殊处理
            else if(parent->_bf==2||parent->_bf==-2)
            {
                
            }
        }
        return true;
    }

特殊处理有4中情况

  • 新节点插入较高左子树的左侧—左左:右单旋

在这里插入图片描述

上图在插入前,AVL树是平衡的,新节点插入到30的左子树(注意:此处不是左孩子)中,30左
子树增加了一层,导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加一层,即将左子树往上提,这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有右子树,右子树根的值一定大于30,小于60,只能将其放在60的左子树,旋转完成后,更新节点的平衡因子即可。在旋转过程中,有以下几种情况需要考虑:
1. 30节点的右孩子可能存在,也可能不存在
2. 60可能是根节点,也可能是子树
如果是根节点,旋转完成后,要更新根节点
如果是子树,可能是某个节点的左子树,也可能是右子树

//右旋和左旋是一样的
    void RotateR(Node* parent)
    {
        Node* subL=parent->left;
        Node* subLR=subL->right;
        Node* pparent=parent->parent;
        parent->left=subLR;
        subL->right=parent;
        if(subLR!= nullptr)
        {
            subLR->parent=parent;
        }
        parent->parent=subL;
        subL->parent=pparent;
        if(pparent== nullptr)
        {
            _root=subL;
        }
        else if(pparent!= nullptr)
        {
            if(pparent->left==parent)
            {
                pparent->left=subL;
            }
            else if(pparent->right==parent)
            {
                pparent->right=subL;
            }
        }
        parent->_bf=subL->_bf=0;
    }
  • 新节点插入较高右子树的右侧—右右:左单旋

在这里插入图片描述

void RotateL(Node* parent)
    {
        Node* subR=parent->right;
        //右子树的左子树
        Node* subRL=subR->left;
        //旋转的这棵树有可能是子树,所以需要保存parent的parent
        Node* pparent=parent->parent;
        parent->right=subRL;
        subR->left=parent;
        //subLR可能不存在,需要单独判断
        if(subRL!= nullptr)
        {
            subRL->parent = parent;
        }
        parent->parent=subR;
        subR->parent=pparent;
        //如果parent不是子树,就需要把_root给subR
        if(pparent== nullptr)
        {
            _root=subR;
        }
        //如果parent是子树的话,需要改变pparent的指向
        else if(pparent!= nullptr)
        {
            //子树是pparent的左子树/右子树,需要把pparent-left/->right指向subR
            if(pparent->left==parent)
            {
                pparent->left=subR;
            }
            else if(pparent->right==parent)
            {
                pparent->right=subR;
            }
        }
        //更新平衡因子
        subR->_bf=parent->_bf=0;
    }
  • 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

在这里插入图片描述

注意:要提前记录60的平衡因子,60这个结点的平衡因子如果是-1,90的平衡因子就会+1,30、60的平衡因子是0,如果平衡因子是1的话,30的平衡因子会-1,60,90的平衡因子是0,但如果平衡因子是0的话,那么30,60,90的平衡因子也是0

void RotateLR(Node* parent)
    {
        Node* subL=parent->left;
        Node* subLR=subL->right;
        int bf=subLR->_bf;
        RotateL(parent->left);
        RotateR(parent);
        if(bf==0)
        {
            subL->_bf=0;
            subLR->_bf=0;
            parent->_bf=0;
        }
        else if(bf==1)
        {
            parent->_bf=0;
            subLR->_bf=0;
            subL->_bf=-1;
        }
        else if(bf==-1)
        {
            parent->_bf=1;
            subLR->_bf=0;
            subL->_bf=0;
        }
        else
        {
            assert(false);
        }
  • 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

在这里插入图片描述

void RotateRL(Node* parent)
    {
        Node* subR=parent->right;
        Node* subRL=subR->left;
        int bf=subRL->_bf;
        RotateR(parent->right);
        RotateL(parent);
        //可以都更新为0
        if(bf==0)
        {
            subR->_bf=0;
            subRL->_bf=0;
            parent->_bf=0;
        }
        //bf=1,会导致parent少一个右结点
        else if(bf==1)
        {
            subR->_bf=0;
            parent->_bf=-1;
            subRL->_bf=0;
        }
        //bf=-1,会让subR少一个左结点
        else if(bf==-1)
        {
            subR->_bf=0;
            parent->_bf=0;
            subR->_bf=1;
        }
        else
        {
            //出错
            assert(false);
        }
    }

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

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

相关文章

一个基于 SpringCloud 微服务架构的前后端分离博客系统

项目介绍 蘑菇博客( MoguBlog )&#xff0c;一个基于微服务架构的前后端分离博客系统。Web 端使用 Vue ElementUi , 移动端使用 uniapp 和 ColorUI。 后端使用 SpringCloud SpringBoot Mybatis-plus进行开发&#xff0c;使用 Jwt SpringSecurity 做登录验证和权限校验&am…

统计机器学习第十三章极大似然估计的性质——图解MLE的渐进正态性

n10; t10000; s1/12/n; xlinspace(-0.4,0.4,100); y1/sqrt(2*pi*s)*exp(-x.^2/(2*s)); zmean(rand(t,n)-0.5,2);figure(1); clf; hold on b20; hist(z,b); hplot(x,y*t/b*(max(z)-min(z)),r-);这段代码的功能是生成随机数并进行直方图和曲线的可视化。下面是每行代码的解释&…

[算法前沿]--028-基于Hugging Face -Transformers的预训练模型微调

1. 简介 本章节将使用 Hugging Face 生态系统中的库——🤗 Transformers来进行自然语言处理工作(NLP)。 Transformers的历史 以下是 Transformer 模型(简短)历史中的一些参考点: Transformer 架构于 2017 年 6 月推出。原始研究的重点是翻译任务。随后推出了几个有影响…

Chrome/Edge 浏览器多账号登录,测试同一业务系统的不同账号角色

文章目录 如何使用多账户&#xff1f;ChromeEdge 虽然说用不同浏览器测试也比较方便、还能顺带测试多浏览器兼容问题…… 但我是开发呀&#xff0c;我只想用我最习惯的谷歌浏览器完成快速开发&#xff0c;把功能铺上&#xff0c;专注于业务逻辑的开发 这些浏览器差异等只会给我…

RTSP/Onvif协议视频平台EasyNVR硬件无法进入服务器该如何解决?

EasyNVR是基于RTSP/Onvif协议的视频接入、处理及分发的安防视频云平台&#xff0c;可提供的视频能力包括&#xff1a;设备接入、实时视频直播、录像、云存储、录像回放与检索、告警、级联等&#xff0c;平台可支持将接入的视频流进行全平台、全终端的分发&#xff0c;分发的视频…

占空比任意方波的傅里叶级数展开

目录 傅里叶级数的复数形式占空比任意方波的傅里叶级数展开 常见的方波信号傅里叶级数展开都是占空比为50%&#xff0c;如方波信号傅里叶级数展开&#xff0c;但有的时候信号的占空比不一定是50%的信号&#xff0c;这时我们要对其进行傅里叶变换或者频谱推导的时候&#xff0c;…

Android应用权限请求步骤

1.在AndroidManifest.xml中配置请求权限 <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"/> 2.在onCreate(Bundle savedInstanceStat…

ffmpeg之linux编译

文章目录 一、下载源码二、选项说明三、依赖库四、编译安装 一、下载源码 上官网https://ffmpeg.org/download.html下载源码 二、选项说明 --disable-static&#xff1a;禁止构建静态库&#xff0c;默认关闭&#xff08;即默认构建的是静态库&#xff09;--enable-shared&a…

脉冲离子风棒的工作原理、特点及其应用

脉冲离子风棒是一种独特的清洁工具&#xff0c;它利用高能离子风的冲击力&#xff0c;可以快速而彻底地清洁物体表面静电。本文将介绍脉冲离子风棒的工作原理、特点以及其在清洁领域的应用。 脉冲离子风棒的工作原理是利用高能脉冲电场将气体中的分子电离&#xff0c;并产生离子…

OpenText 企业内容管理平台的亮点及优势

OpenText Extended ECM 平台 将内容服务与领先应用程序集成&#xff0c;以弥合内容孤岛、加快信息流并扩大治理 什么是内容服务集成&#xff1f; 内容服务集成通过将内容管理平台与处于流程核心的独立应用程序和系统连接起来&#xff0c;支持并扩展了 ECM 的传统优势。 最好的…

Itext 7 生成pdf带有背景图

Itext 7 生成pdf带有背景图并下载PDF到本地 引入jar包 <dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.0.3</version><type>pom</type></dependency>代码实现 Get…

unity场景名对象在Inspector面板以下拉列表显示

unity场景名对象在Inspector面板以下拉列表形式显示&#xff0c;避免输入错误。 首先创建一个类用来获取BuildSetting中场景列表中的所有场景名字 public class MSceneName : PropertyAttribute {/// <summary>/// 场景名列表/// </summary>public string[] Name…

Linux驱动学习(4) MTD字符驱动和块驱动2

系列文章目录 Linux驱动学习&#xff08;4&#xff09; MTD字符驱动和块驱动1 Linux驱动学习&#xff08;4&#xff09; MTD字符驱动和块驱动2 Linux驱动学习&#xff08;4&#xff09; MTD字符驱动和块驱动3 文章目录 目录 系列文章目录 文章目录 前言 一、mtd字符设备…

react antd阻止Checkbox事件冒泡(折叠面板标题中增加复选框,阻止点击复选框折叠面板展开/折叠)

背景 折叠面板Collapse标题中增加复选框&#xff0c;点击复选框&#xff0c;会触发折叠面板的展开和折叠。 我们希望勾选复选框的时候&#xff0c;不能影响到折叠面板的展开和折叠。 最开始使用onChange自带的event来阻止事件冒泡&#xff0c;这种方式是无效的&#xff0c;代…

安卓应用的图标设计

参考链接&#xff1a;https://developer.android.com/studio/write/create-app-icons 安卓的图标比较复杂&#xff0c;因为有很多图标。可以用一张自己的图做图标&#xff0c;本文介绍其过程。 运行image asset studio&#xff0c;在android studio中&#xff0c;项目栏中&…

芒果在线咸鱼转转交易猫聊天客服源码

芒果在线咸鱼转转交易猫聊天客服源码是一款为咸鱼转转定制的客服系统&#xff0c;具备前后台管理功能&#xff0c;还支持咸鱼转转模板和分享图功能。本文将介绍该客服系统的安装方法&#xff0c;以及如何修改公告内容和机器人自动回复内容。

Redis异常报错出现 WRONGTYPE Operation against a key holding the wrong kind of value

操作Redis做一个查询优化的时候出现一个问题&#xff1a; org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: WRONGTYPE Operation against a key holding the wrong kind of v…

发现好工具nodepad-- 你没有看错是--

工欲善其事&#xff0c;必先利其器 这是一个使用C编写的文本编辑器Notepad--,可以支持Win/Linux/Mac平台。 他们的目标是要进行文本编辑类软件的国产可替代&#xff0c;重点在国产Uos/Linux系统、Mac 系统上发展。 一个支持windows/linux/mac的文本编辑器&#xff0c;目标是…

百家号关键词榜怎么上?排名规则是什么?

百家号关键词榜怎么上?排名规则是什么?#百家号关键词排名 #百家号v认证 #百家号代运营 #百家号排名技巧 如何利用百家号关键词排名实现“百度首页霸屏”&#xff1f;#百度霸屏技术 今天给大家介绍一下百度百家号是百度为内容创作者提供的内容发布、内容变现和粉丝管理平台。 …

统信UOS1060版本安装时选择【免费使用授权】安装的方法

1.选择界面化进行安装操作。 2.在选择授权类型中选择【免费使用授权】即可&#xff0c;根据其他提示进行选择安装目的地及根密码root密码的设置。 3.剩下的就是下一步下一步进行安装。