平衡二叉树旋转详解

2023-05-16

  • 平衡二叉树的定义(AVL)定义
    平衡二叉树或者是一棵空树,或者满足以下的性质:它的左子树和右子树的高度之差的绝对值不超过1,并且左子树和右子树也是一个平衡二叉树。

  • 平衡因子
    左子树高度减去右子树的高度的值或者右子树高度减去左子树高度的值。显然 -1 <=bf <= 1

  • AVL树的引入
    平衡二叉树在二叉排序树上引入的,在二叉树中,如果插入的节点接近有序,那么二叉树就会退化为链表大大降低了查找效率,为了使二叉树无论什么情况下最大限度的接近满二叉树,从而保证它的查找效率,因此引入平衡二叉树。

  • AVL树的实现
    如何保证二叉树在任何情况下都能最大限度接近满二叉树,从而保证它的查找效率呢?那就是旋转,当平衡因子的绝对值大于1的时候,我们就需要对其进行旋转。

  • 旋转步骤详解
    我们只需要理清需要旋转的情况,掌握旋转的要素,找到其中的规律,就能轻松地写出AVL树的代码了,下面我详细的给出旋转的情况与步骤,大家仔细观察找出其中的规律。(此例中的平衡因子bf采用的是右子树的高度减去左子树的高度
    左左(LL)(右旋)
    这里写图片描述
    这里写图片描述
    这里写图片描述

    针对于在较高左子树的左侧插入节点的这种情况大家发现了什么规律呢?我们发现在插入之前Parent是离插入节点最近有可能失衡的节点,对于LL的三种情况我们发现插入节点导致失衡后图示(Parent) 节点平衡因子为-2,他的左孩子(SubL)为-1,进行右旋了之后Parent 以及 SubL节点的平衡因子都变成了0。通过这些规律我们来实现右旋的代码
    右旋操作代码

void rRotate(Node *Parent)//LL
    {
        Node *subL = Parent->_pLeft;
        Node *subLR = subL->_pRight;
        Parent->_pLeft = subLR;
        if (subLR)//左单支
            subLR->_parent = Parent;
        subL->_pRight = Parent;
        Node *pParent = Parent->_parent;
        Parent->_parent = subL;
        subL->_parent = pParent;
        if (NULL == pParent)//Parent是根节点
            _pRoot = subL;
        else if (Parent == pParent->_pLeft)
            pParent->_pLeft = subL;
        else
            pParent->_pRight = subL;
        //修改平衡因子
        subL->_bf = 0;
        Parent->_bf = 0;
    }

右右(RR)左旋
这里写图片描述
这里写图片描述
这里写图片描述
针对于在较高右子树的右侧插入节点的这种情况大家发现了什么规律呢?我们发现在插入之前Parent是离插入点最近有可能失衡的节点,对于RR的三种情况我们发现插入节点导致失衡后图示(Parent) 节点平衡因子为2,他的右孩子(SubR)为1,进行左旋了之后Parent 以及 SubR节点的平衡因子都变成了0。通过规律写出RR情况左旋的代码。

void lRotate(Node *Parent)//RR
    {
        Node *subR = Parent->_pRight;
        Node *subRL = subR->_pLeft;
        Parent->_pRight = subRL;
        if (subRL)
        subRL->_parent = Parent;
        subR->_pLeft = Parent;
        subR->_parent = Parent->_parent;
        Parent->_parent = subR;
        Node *pParent = subR->_parent;
        if (NULL == pParent)
            _pRoot = subR;
        else if (Parent == pParent->_pLeft)
            pParent->_pLeft = subR;
        else
            pParent->_pRight = subR;
        Parent->_bf = 0;
        subR->_bf = 0;
    }

左右(LR)
这里写图片描述
这里写图片描述
这里写图片描述
针对于在较高左子树的右侧插入节点的这种情况大家发现了什么规律呢?我们发现在插入之前Parent是离插入点最近有可能失衡的节点,对于LR的三种情况我们发现插入节点导致失衡后图示(Parent) 节点平衡因子为-2,他的左孩子(SubL)为1,插入及旋转发现旋转之前SubLR为-1,旋转之后Parent为1,SubLR为0,旋转之前SubLR为1,旋转之后SubL为-1,SubLR为0,通过规律写出LR情况左旋的代码。

void lrRotate(Node *Parent)//LR
    {
        Node *subL = Parent->_pLeft;
        Node *subLR = subL->_pRight;
        int bf = subLR->_bf;
        lRotate(Parent->_pLeft);
        rRotate(Parent);
        if (1 == bf)
            subL->_bf = -1;
        else if (-1 == bf)
            Parent->_bf = 1;
           subLR->_bf = 0;
    }

右左(RL)
这里写图片描述
这里写图片描述
这里写图片描述
针对于在较高右子树的左侧插入节点的这种情况大家发现了什么规律呢?我们发现在插入之前Parent是离插入点最近有可能失衡的节点,对于RL的三种情况我们发现插入节点导致失衡后图示(Parent) 节点平衡因子为2,他的右孩子(SubR)为-1,插入及旋转发现旋转之前SubLR为-1,旋转之后SubR为1,SubLR为0,旋转之前SubRL为1,旋转之后Parent为-1,SubLR为0,通过规律写出RL情况的代码。

void rlRotate(Node *Parent)
    {
        Node *subR = Parent->_pRight;
        Node *subRL = subR->_pLeft;
        int bf = subRL->_bf;
        rRotate(Parent->_pRight);
        lRotate(Parent);
        if (1 == bf)
            Parent->_bf = -1;
        else if (-1 == bf)
            subR->_bf = 1;
        subRL->_bf = 0;
    }

综上我们不难总结出AVL树插入的规律
这里写图片描述

  • AVL树插入代码
bool Insert(const K& key, const V& value)
    {
        Node *pNew = new Node(key,value);
        Node *pCur = _pRoot;
        Node *parent = NULL;
        if (NULL == _pRoot)
        {
            _pRoot = pNew;
            return true;
        }
        while (pCur)//寻找插入位置
        {
            if (key < pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (key > pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }
        if (key < parent->_key)//插入元素
            parent->_pLeft = pNew;
        else
            parent->_pRight = pNew;
        pNew->_parent = parent;
        //修改平衡因子
        while (parent)
        {
            if (pNew == parent->_pLeft)
                parent->_bf--;
            else
                parent->_bf++;
            if (0 == parent->_bf)
                return true;
            else if (1 == parent->_bf || -1 == parent->_bf)
            {
                pNew = parent;
                parent = parent->_parent;
            }
            else//2需要进行旋转
            {
                if (-2 == parent->_bf && -1 == pNew->_bf)//LL
                    rRotate(parent);
                else if (2 == parent->_bf && 1 == pNew->_bf)//RR
                    lRotate(parent);
                else if (-2 == parent->_bf && 1 == pNew->_bf)//LR
                    lrRotate(parent);
                else if (2 == parent->_bf && -1 == pNew->_bf)//RL
                    rlRotate(parent);
                return true;
            }
        }
        return true;
    }

完整代码请戳
https://coding.net/u/Hyacinth_Dy/p/MyCode/git/blob/master/AVLBinaryTree

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

平衡二叉树旋转详解 的相关文章

  • MissionPlanner使用说明(持续更新)

    MissionPlanner有些功能需要自己摸索 xff0c 我把一些比较难找的功能使用方法列举如下 xff1a 原文链接 xff1a http www nufeichuiyun com p 61 67
  • 怒飞垂云视频教程 一、建立编译环境

    本文讲述如何建立APM飞控固件的编译环境 原文链接 xff1a http www nufeichuiyun com p 61 237
  • Android Automotive(七) VehicleService

    Android Automotive xff08 七 xff09 VehicleService VehicleService 是Android Automotive在硬件抽象层的一个核心native服务 处理和车辆相关功能 xff0c 为系
  • ardupilot之添加mavlink消息

    本文是这篇文章的复现 xff1a http www sohu com a 213599378 175233 一 mavlink分析 Mavlink 的全称是Micro Air Vehicle link xff0c pixhawk把它作为与地
  • Linux中断机制:硬件处理,初始化和中断处理

    来源 CSDN phenix lord的专栏 硬件处理 最近解决一个关于Linux中断的问题 xff0c 把相关机制整理了一遍 xff0c 记录在此 不同的外部设备 不同的体系结构 不同的OS其中断实现机制都有差别 xff0c 本文对应的O
  • 跟我一起复制一款基于ESP-Drone无人机控制板

    1 ESP Drone 无人机项目简介 ESP 无人机是基于ESPRESIF ESP32 ESP32 S2 Wi Fi芯片的开源解决方案 xff0c 可通过Wi Fi连接到手机应用程序或游戏控制台 ESP无人机具有简单的硬件 清晰和可扩展的
  • linux安装llvm

    先装cmake xff0c 可以用sudo apt get install cmake或者去官网下载源码编译安装 下载llvm git clone https github com llvm llvm project git 3 Build
  • Makefile中的MAKECMDGOALS

    make 在执行时会设置一个特殊变量 xff1a 34 MAKECMDGOALS 34 xff0c 该变量记录了命令行参数指定的终极目标列表 xff0c 没有通过参数指定终极目标时此变量为空 该变量仅限于用在特殊场合 比如判断 xff0c
  • Docker切换存放目录踩坑

    因为 var 目录下的磁盘空间不足 xff0c 故把docker的存放目录切换到 data 下面 xff0c 具体步骤 xff1a 1 编辑docker配置文件 etc docker daemon json xff0c 修改data roo
  • 关于Modelsim SE-64 2020.4取消优化后不显示波形问题

    Modelsim取消优化后报错 Error suppressible vsim 12110 All optimizations are disabled because the novopt option is in effect This
  • 关于串口调试助手XCOM点击发送后卡住问题

    未成功安装CH340驱动 USB串口驱动 安装前先重启电脑 xff0c 再点击安装 串口选择错误 打开设备管理器 xff0c 查看USB连接的端口 xff08 COM xff09 号 xff0c 选择正确的端口 xff08 COM xff0
  • Makefile中Linux转Windows执行知识点

    makefile 是一个自动化编译工具 xff0c 可以简化编译过程 xff0c 自动化处理依赖关系和编译顺序 xff0c 提高了代码的可维护性 makefile 通常由一些规则和命令组成 xff0c 规则由目标 依赖和命令构成 xff0c
  • darknet2ncnn编译中 libopencv 库文件找不到

    问题描述 没有直接从 github 上下载 darknet2ncnn 包 xff0c 用的是他人提供的包 xff0c 包已经编译好 解压已经有 convert verify 文件 执行该文件 xff0c 问题描述如下 xff1a root
  • linux usb设备如何和u盘对应

    已知 usb 的 pid vid 如何对加载的u盘进行管理 思路 xff0c 找到 U盘的厂商信息中的pid和 vid 对应关系 xff0c 然后控制 U盘的加载 但是 U盘信息中没有pid 和 vid root 64 li PC sys
  • CV面试题(持续更新!!!)

    CV面试题 1 反卷积 反卷积又叫做转置卷积 xff0c 在计算机中计算的时候 xff0c 转置卷积先将卷积核转为稀疏矩阵C的形式 xff0c 然后计算的时候正向传播的时候左乘这个稀疏矩阵C的转置 xff0c 反向传播的时候左乘这个稀疏矩阵
  • 程序运行时数据保存位置

    程序运行时 xff0c 内存中有六个地方可以保存数据 1 寄存器 这是最快的保存区域 xff0c 寄存器位于处理器内部 然而寄存器的数量很有限 xff0c 所以寄存器是根据需要由编译器的分配的 我们对此没有直接的控制权限 也不可能在我们的程
  • ESP-Drone无人机控制板设计的第一个任务---绘制ESP32-S2-WROVER模块及周边电路

    第1步 xff0c 查看官方ESP Drone无人机ESP32 S2 WROVER模块的参考设计原理图 第二步 xff0c 用KiCAD绘制ESP32 S2 WROVER模块及周边电路 1 如图2 1所示 xff0c 从KiCAD的原理图符
  • ROS学习——读取摄像头数据image

    在ROS工作空间的src文件夹下创建read camera功能包 xff0c 并在包内创建include launch src cfg四个文件夹 在cfg文件夹中创建param yaml文件 xff0c 并写入以下内容 xff1a imag
  • ROS学习——控制小车转向

    给定一个旋转的角度 xff0c 让小车进行顺时针或逆时针旋转 span class token macro property span class token directive keyword include span span clas
  • PID参数设定

    在电机的控制领域 xff0c 不同的电机有不同的驱动方式 xff0c 其中应用最广泛的就是PID proportion integration differentiation 控制 P I和D分别指比例控制 xff0c 积分控制和微分控制

随机推荐

  • 系统编程__2__父子进程的创建和回收

    系统编程 这里写的是对于小白来说更多的了解系统编程的文章 xff0c 有写的不对的地方还恳请各位大佬指出错误 xff0c 小编一定会多多采纳 手动多谢 那么 xff0c 上一次我们稍微了解了一下关于系统编程的一些主要内容 没有看到的童鞋还请
  • php解决跨域访问

    php跨域问题解决判断 参考文章 xff1a php跨域 xff1a https blog csdn net ouxiaoxian article details 89332027 预检请求是什么 xff1a https www jians
  • 动态库与静态库的区别是什么

    区别 xff1a 1 静态库的扩展名一般为 a 或 lib xff1b 动态库的扩展名一般为 so 或 dll 2 静态库在编译时会直接整合到目标程序中 xff0c 编译成功的可执行文件可独立运行 xff1b 动态库在编译时不会放到连接的目
  • Ubuntu 使用 du 查看某个文件夹大小

    在 Ubuntu 系统中 xff0c 你可以使用 du 命令来查看文件夹的大小 例如 xff0c 如果你想查看文件夹 var log 的大小 xff0c 你可以使用如下的命令 xff1a du sh var log 其中 xff0c s 选
  • 无人机六旋翼数学建模[matlab-simulink]

    写在前面 xff0c 这篇文章是借鉴Drexel University 的Senior Design project的matlab simulink四旋翼模型 xff0c 在此基础上针对六旋翼进行的基本改进 xff0c 这里只对 43 型模
  • stm32连接DHT11温湿度传感器

    目录 1 DHT11简介 1 1 连接电路 1 2 串行接口 单线双向 2 cubeMX设置 3 代码开发 3 1 实现定时函数 3 2 打开串口调试 3 4 测试代码实现 4 运行效果 1 DHT11简介 1 1 连接电路 信息如下 xf
  • STM32CubeMX 真的不要太好用

    STM32CubeMX 真的不要太好用 由于工作内容的变动 xff0c 我已经很久没有正经的玩过单片机了 xff0c 近期又要用它做个小玩意了 xff0c 还是选 stm32 吧 xff0c 外设库开发不要太方便 xff0c 哈哈哈 先去
  • ESP-Drone控制板设计的第二个任务-绘制USB-TTL串口下载电路和ESP32-S2芯片内置USB接口电路

    1 摘要 ESP32系列处理器一般会需要采用串口来下载代码 xff0c 因此在其设计中都会保留一个USB TTL串口电路 xff0c 查看乐鑫官网的参考设计 xff0c 基本上是采用CP2102这颗USB转TTL串口芯片 xff0c 但在本
  • Airflow ETL任务调度工具 介绍

    Airflow 是 Apache 基金会的一套用于创建 管理和监控工作流程的开源平台 xff0c 是一套非常优秀的任务调度工具 截至2022年7月 xff0c 在GitHub上已经拥有近27k的star 本文主要介绍一下Airflow 2
  • Data_web(八)mysql增量同步到mongodb

    1 mongdb连接 连接方式如下 xff08 重要 xff01 xff01 xff01 xff01 xff0c 账号密码必须建立在db下面 xff0c 如果默认再admin下面 xff0c 导致无法切换库 xff0c 连接报错 xff09
  • 2021电子设计竞赛飞控视觉之openmv寻找方格中心

    写在前面 这是我在电赛飞控备赛期间写的一个小函数 xff0c 功能是寻找目标点所在方格的中心 这样四旋翼在方格地图上移动一定距离之后就可以使用openmv将四旋翼辅助定位至目前所在方格的中心 今年G题刚出来的时候本来以为能用上这个函数进行辅
  • centos6.5vim基本配置

    简单的vim配置 xff1a 在目录 etc 下面 xff0c 有个名为vimrc的文件 xff0c 这是系统中公共的vim配置文件 xff0c 对所有用户都有效 而在每个用户的主目录下 xff0c 都可以自己建立私有的配置文件 xff0c
  • atexit注册函数

    函数名 atexit 头文件 include lt stdlib h gt 功 能 注册终止函数 即main执行结束后调用的函数 用 法 int atexit void func void 注意 xff1a 按照ISO C的规定 xff0c
  • Linux管道的容量大小及管道的数据结构

    一 管道容量 xff1a 我们通过ulimit a 命令查看到的pipo size定义的是内核管道缓冲区的大小 xff0c 这个值的大小是由内核设定的 xff1b 而pipe capacity指的是管道的最大值 xff0c 即容量 xff0
  • 线程初体验

    线程的概念 xff1a 线程是一个进程地址空间的一个控制流程 xff0c 是调度的基本单位 xff0c 由于同一进程的多个线程共享同一地址空间 因此Text Segment Data Segment都是共享的 如果定义一个函数 在各线程中都
  • 死锁的四个必要条件

    死锁产生的四个必要条件 互斥条件 xff1a 资源是独占的且排他使用 xff0c 进程互斥使用资源 xff0c 即任意时刻一个资源只能给一个进程使用 xff0c 其他进程若申请一个资源 xff0c 而该资源被另一进程占有时 xff0c 则申
  • 线程安全与可重入函数的区别

    线程安全 xff1a 一般来讲就是一个代码块被多个并发线程反复调用时会一直产生正确的结果 如何确保线程安全 xff1a 确保线程安全 主要 考虑线程之间共享变量的安全 xff0c 每个线程私有的内容包括 xff1a 线程id xff0c e
  • Linux模拟实现sleep

    工作原理 linux中的sleep函数能够让程序休眠一定的秒数 xff0c 到时间后自动恢复运行 实现思路 设定睡眠的秒数 睡眠 xff08 挂起 xff09 恢复运行实现机制 设定睡眠的秒数 xff1a 采用alarm 函数设定需要睡眠的
  • 基于ESP32C3处理器创建Hello World工程-并使用OpenOCD进行Debug

    1 编程环境 1 1 硬件 序号 名称 描述 备注 1 ESP C3 12F KIT 深圳安信可开发的基于其自家ESP C3 12F模块的开发板 淘宝购买 2 ESP Prog 乐鑫官方推出基于FT2232HL接口芯片的JTAG调试器 淘宝
  • 平衡二叉树旋转详解

    平衡二叉树的定义 xff08 AVL xff09 定义 平衡二叉树或者是一棵空树 xff0c 或者满足以下的性质 xff1a 它的左子树和右子树的高度之差的绝对值不超过1 xff0c 并且左子树和右子树也是一个平衡二叉树 平衡因子 左子树高