AVL树的旋转

AVL树的四种旋转方式(详细图解) 新节点插入到左子树的右侧时对parent使用左右双旋。新节点插入到右子树的左侧时对parent使用右左双旋。新节点插入到右子树的右侧时对parent使用左单旋。新节点插入到左子树的左侧时对parent使用右单旋。 阅读详情
AI摘要

本文详细介绍了AVL树的定义、平衡因子和旋转原理,包括左单旋转、右单旋转及双旋转的情况分析,并给出了具体的旋转代码实现。通过实例展示了在不同插入位置时如何保持AVL树的平衡,确保其高度对数复杂度。

定义

        一棵AVL树可以是空树,也可以是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1(也就是小于等于1)。(右子树高度 - 左子树高度)

        节点的平衡因子:给每个节点附加一个数字,给出该节点右子树的高度减去左子树的高度所得的高度差,这个数字即为节点的平衡因子。

        如果一棵二叉搜索树的高度是平衡的,它就成为了AVL树,如果它有n个节点,其高度可保持在O(log2n)。

AVL树的旋转

        平衡化旋转:
                ① 如果在一棵平衡的二叉搜索树中插入一个新节点,造成了不平衡。此时必须调整树的结构,使之平衡化。

                ② 平衡化旋转有两类:单旋转和双旋转。

                其中单旋转又可分为左单旋转和右单旋转。

        每插入一个新节点时,AVL树中相关的平衡状态会发生改变,因此,在插入一个新节点后,需要从插入的位置沿向根的路径回溯,检查各节点的平衡因子。

        如果在某一节点发现高度不平衡,停止回溯,从发生不平衡的节点起,沿刚才回溯的路径直接下两层的节点,如果这三个节点处于一条直线上,则采用单旋进行平衡化。单旋转可按其旋转方向分为左单旋转和右单旋转,其中一个是另一个的镜像,其旋转方向与不平衡的形状有关。

        如果这三个节点处于一条折线上,则采用双旋转进行平衡化。双旋转分为先左后右和先右后左两类。

左单旋转

        如图,此时这棵树是一根平衡的二叉搜索树,所以我们也可以称这棵树为AVL树。每个节点的平衡因子用红色字体标出。我们可以看到,每个节点的平衡因子的绝对值都没有超过1.此时该树平衡。
在这里插入图片描述

        此时,我们插入新的节点,节点值为85,我们发现,50这个节点的平衡因子超过1了。这棵树已经是不平衡的了,如下图所示:
在这里插入图片描述
        根据我们的旋转规则:从新加入的节点开始沿根的路径回溯,找到不平衡的节点,从这个不平衡的节点开始沿刚才回溯的路径向下寻找两层节点,如果这三个节点在同一直线上,我们就是用单旋转,否则使用双旋转。依据这个规则,我们找到了不平衡的节点50,向下两层找到了节点70、节点80。这三个节点在同一直线上,所以我们采用单旋转。

        以不平衡节点的下一个节点为旋转点,进行左单旋转:如图所示:
在这里插入图片描述
        如上图所示,我们首先定义一个ptr引用指向不平衡的节点,然后它的右孩子,是我们旋转后的根节点,我们将它定义为newRoot

        具体是怎么旋转的,我们来看看下图:
在这里插入图片描述
        具体代码实现:

// AVL树的结构与二叉搜索树的结构相似,只是多了一个 int balance遍历表示平衡因子。
// 这里AVL树的结构就不再给出。直接给出坐旋转的代码。

    public void rotateLeft(ANode ptr){
        ANode newRoot = ptr.rightChild; // ①
        newRoot.parent = ptr.parent; // 维护newRoot的双亲。

        // 维护newRoot.leftChild的双亲。
        if (newRoot.leftChild!=null) {
            newRoot.leftChild.parent = ptr;
        }
        ptr.rightChild = newRoot.leftChild;//③


        newRoot.leftChild = ptr; // ②
        ANode pa = ptr.parent;
        // pa == null 说明旋转前,ptr就是根节点
        if (pa==null){
            root = newRoot;
        }else{
            // pa != null 说明ptr要么是上一棵AVL树的左子树
            // 要么是上一棵AVL树的右子树。
            if (pa.leftChild == ptr){
                pa.leftChild = newRoot;
            }
            if (pa.rightChild == ptr){
                pa.rightChild = newRoot;
            }
        }
        
        //维护ptr的双亲
        ptr.parent = newRoot;
    }

右单旋转

        右单旋转和左单旋转的思路是一样的,只不过是旋转的方向不同,我们还是用图示来说明。

        如图,此时是一棵平衡的AVL树。
在这里插入图片描述

        当我们向这棵AVL树中添加 节点10时,如下图所示:
在这里插入图片描述
        此时,我们从新插入的节点10开始,沿着根路径向上回溯的查找,直到查找到80这个节点,发现该节点的平衡因子的绝对值大于1,于是,从该节点向下,沿着刚才回溯的路径,找到下两层节点40、30。这三个节点在同一条直线上,此时以40这个节点为旋转点,进行右单旋转。

        如下图:
在这里插入图片描述
        代码实现:

    // AVL树右单旋转
    public void rotateRight(ANode ptr){
        ANode newRoot = ptr.leftChild;
        newRoot.parent = ptr.parent; //维护newRoot的双亲
        
        //维护newRoot.rightChild的双亲
        if (newRoot.rightChild!=null){
            newRoot.rightChild.parent = ptr;
        }
        ptr.leftChild = newRoot.rightChild;

        newRoot.rightChild = ptr;
        ANode pa = ptr.parent;
        if (pa == null){
            root = newRoot;
        }else{
            if (pa.rightChild == ptr){
                pa.rightChild = newRoot;
            }
            if(pa.leftChild ==ptr){
                pa.leftChild = newRoot;
            }
        }
        ptr.parent = newRoot; //维护ptr的双亲
    }

双旋转

        若某一个节点的平衡因子发生改变,沿着回溯路径,以最后一层的节点为旋转点,进行先左单旋后右单旋,或者进行先右单旋后左单旋。

        现有一棵AVL树,每个节点的平衡因子的绝对值 都没有超过1,所以该AVL是平衡的。
在这里插入图片描述

        此时,我们新节点插入的位置有四种,分别为上述图中标出来的1、2、3、4这四个位置。

        情况一:
        首先分析,如果我们插入的位置为1或者2这两个位置其中之一,则有:
在这里插入图片描述

        此时,我们发现无论我们插入的是1位置 还是 2位置,节点B的平衡因子都会变成-1,而节点A的平衡因子都会变成-2。都会导致AVL树不平衡,需要旋转。

        我们从新插入的节点开始,向上回溯至不平衡节点的位置,找到了A节点,于是按照旋转规则:找到刚才回溯路径包括A节点在内的3个节点,即A、B、D开始进行旋转。 即,如果我们新的节点插入到1或者2这两个位置其中之一,我们需要旋转的条件就是:当B的平衡因子变为-1时,我们就要进行单旋转,再进行完单旋转后,我们还需要对B的平衡因子重新赋值。

        我们上面分析过了,无论插入1还是2位置,只是进行单旋转,如下图:
在这里插入图片描述

在这里插入图片描述

        我们发现了一个有意思的事情,无论新插入的节点插入1位置还是2位置,在旋转前,B的平衡因子都会变为-1,而在旋转后,B的平衡因子会变为0,A的平衡因子也会变为0。声明一点:图中没有标注ptr和newRoot两个引用,ptr和newRoot的指向和右单旋转是一样的。

        情况二:

        当我们新节点插入的是3位置
在这里插入图片描述
        此时,B的平衡因子变为1,E的平衡因子变为-1。从新插入节点F处开始向上查找不平衡的节点,找到了A,于是按照遍历规则,A及其下两层的节点要进行旋转。由于A、B、E这三个节点不在一条直线上,所以我们需要双旋转。先以E节点为旋转点,EB进行左单旋转。如图所示:

在这里插入图片描述
        接着,再以E为旋转带你,EA为轴进行右单旋转,如图:
在这里插入图片描述
        此时,我们发现,E的平衡因子变为0,A的平衡因子变为1。

        整体旋转过程如图所示:
在这里插入图片描述
        情况三:

        当新节点插入的位置在4号位置时,如图所示:此时,B的平衡因子还是变为1,E的平衡因子变为了 1 。
在这里插入图片描述
        于是,我们接着按照旋转规则,从新插入节点F处向上查找不平衡的节点,找到A节点,然后A节点向下两层找到A、B、E三个节点,这三个节点不在一条直线上,我们需要进行双旋转。

        首先,以E为旋转点,EB进行左单旋,如图所示:
在这里插入图片描述
        再以E为旋转点,EA进行右单旋,如图:此时我们发现E的平衡因子为0,A的平衡因子为0,B的平衡因子为-1。
在这里插入图片描述
        整体流程如图所示:
在这里插入图片描述
        至此,我们分析完了所有情况,我们回顾一下,三种不同情况各节点的平衡因子变化情况:

        情况一:新节点插入1位置
在这里插入图片描述

        情况一:新节点插入2位置

在这里插入图片描述
        我们发现,节点A和节点B的平衡因子都变为了0,其余节点的平衡因子都没有发生改变。

        我们再来看看情况二,新节点插入3位置:我们发现,A、B、E三个节点的平衡因子都发生了改变。
在这里插入图片描述
        我们再来看看情况三,新节点插入4位置:我们发现,同样的是A、B、E三个节点的平衡因子发生改变。其余节点的平衡因子没有发生改变。
在这里插入图片描述
        代码实现:

    // AVL树的左平衡
    public void leftBalance(ANode ptr){
        ANode leftSub = ptr.leftChild;
        ANode rightSub = null;
        switch(leftSub.balance){
            // 说明新插入节点的位置在1位置或2位置
            case -1:
                leftSub.balance = 0;
                ptr.balance = 0;
                rotateRight(ptr);
                break;
            case 0:
                System.out.println("the tree is balance");
                break;

            // 说明新插入的节点的位置在3位置或4位置,具体情况还要分析
            case 1:
                 rightSub = leftSub.rightChild;
                 switch (rightSub.balance){
                     // 说明插入的是3位置
                     case -1:
                        ptr.balance = 1;
                        leftSub.balance = 0;
                     // 说明插入的是4位置
                     case 1:
                         ptr.balance = 0;
                         leftSub.balance = -1;
                     case 0:
                         ptr.balance = 0;
                         leftSub.balance = 0;
                 }
                 rightSub.balance = 0;
                 rotateLeft(leftSub);
                 rotateRight(ptr);
                 break;
        }
    }

        以上就是我们的双旋转的一种情况:先左单旋转后右单旋转,第二种情况:先右单旋转后左单旋转这里就不再做演示了。和先左后右旋转是一样的思路。如过程中有不对的地方,希望各位能够指点,谢谢!

浅析AVL树--AVL树的双旋转 潜析AVL树–AVL树的双旋转 接上篇博文:简析AVL树–AVL树的概念及单旋转 AVL树如何恢复平衡之双旋转 首先假设我们有一颗已经处于平衡的AVL树: 上篇博文已经解决了LL和RR两种情况的平衡恢复解决方案----单旋转。这篇博文来看双旋转情形。这时候我们插入结点7,我们可以发现这时这棵树并没有失去平衡: 但是,如果我们继续插入结点8,这棵树就会再次处于失衡状态: 我们首先可以发现结点9... 阅读详情

相关推荐

AVL树旋转及代码实现

    AVL树是带有平衡条件的二叉查找树,它允许每个节点的左子树与右子树的高度差未1。这样的平衡树深度是O(log N)。而要维持这种平衡,就必须在每次对AVL树删除节点或新增节点后,检查AVL树的平衡是否被打破,即是否存在节点的左右子树高度差大于1,在判断AVL树失去平衡后,就必须旋转失去平衡的节点,已再次达到平衡。AVL树旋转:    旋转的目的就是减小树的高度,节点未空时,节点的高度未-1...

ybin__的博客 968

AVL树的旋转操作详解

图解AVL平衡二叉树的旋转

张小凡 2520

遗传算法详解 附python代码实现

遗传算法 遗传算法是用于解决最优化问题的一种搜索算法。从名字来看,遗传算法借用了生物学里达尔文的进化理论:”适者生存,不适者淘汰“,将该理论以算法的形式表现出来就是遗传算法的过程。 问题引入 上面提到遗传算法是用来解决最优化问题的,下面我将以求二元函数: def F(x, y): return 3*(1-x)**2*np.exp(-(x**2)-(y+1)**2)- 10*(x/5 - x**3......

ha_ha_ha233的博客 22万+

【C++AVL树】4种旋转详讲

如果还没有元素是一课空树,直接插入即可;如果有元素,按pair的first(key)和比较的节点比较结果为大说明为空的哪个位置在右边,和比较的节点比较的结果小说明为空的哪个位置在左边,如果相等说明已经有这个元素了,二叉搜索树不支持冗余,插入失败返回false; 不知道这个已经找到的位置在父节点的左边还是右边,需要判断一下,然后插入元素; 插入元素的后那么平衡因子将发生变化,为0说明这个父亲节点左右平衡不会影响其他节点,为1或者-1需要向上调整,为2或者-2说明已经不平衡需要旋转;

m0_72964546的博客 1385

3D IC中Memory-on-Logic堆叠测试的DFT解决方案与工程实践

在半导体行业,随着摩尔定律逼近物理极限,3D IC技术通过芯片垂直堆叠实现性能提升和异构集成,已成为重要发展方向。其核心原理是利用硅通孔(TSV)或微凸块实现芯片间电气互连,将多个不同功能的芯片(如逻辑芯片与存储芯片)集成在一个封装内。这项技术的核心价值在于能大幅提升系统性能、降低功耗并实现更小的封装尺寸。然而,芯片堆叠后,传统的测试方法面临巨大挑战,尤其是测试访问存在物理屏障,无法直接探测被覆盖的芯片接口。为此,可测试性设计(DFT)成为确保3D IC可靠性与量产可行性的关键技术。它通过在设计阶段植入专用

weixin_42521058的博客 632

基于Open Cluster Management构建企业级多Kubernetes集群管理平台OpenClaw

在云原生架构中,Kubernetes已成为容器编排的事实标准。随着业务规模扩大,企业往往需要管理分布在多个云环境或数据中心的Kubernetes集群,这带来了集群管理、应用分发、策略统一和监控运维等复杂挑战。多集群管理技术通过提供统一控制平面,实现了对分布式资源的集中管控,其核心价值在于提升运维效率、保障安全合规并降低管理成本。Open Cluster Management(OCM)作为CNCF沙箱项目,采用Kubernetes原生架构,通过自定义资源定义(CRD)和控制器模式,为构建多集群管理平台提供了标

weixin_33747129的博客 368

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构(这会导致我们查询的时间复杂度变为O(n)),然而AVL树就很好的解决了这一问题(归功于四种旋转的方法),它让我们的树的查询的时间复杂度变得接近于甚至等于O(logN)。它相比于普通的二叉搜索树,它增加了平衡因子来维持树的高度,增加了纸箱上一个节点的parent指针。另外,平衡因子的计算方法是右子树的高度减去左子树的高度,当当前节点的平衡因子的值为-1、0、1的时候,我们认为当前节点是平衡的,当为其他值的时候就不平衡,需要通过旋转来将树调整平衡。

2301_79972085的博客 1657

用GraphPad Prism直出单细胞亚群堆叠柱状图

用GraphPad Prism直出单细胞亚群堆叠柱状图

fivehuge的博客 4197

浅谈树旋转

浅谈树旋转1.概述2.旋转2.1 总览2.2 右旋2.3 左旋3.代码 1.概述 树旋转,是 AVL 树和 Splay 等平衡树控制平衡的一种办法,同时也在别的领域有着重要的应用。 那么什么是树旋转呢?又有什么类型呢? 2.旋转 2.1 总览 比如下面这两棵树,上面的树对 0 号节点右旋后成为下面的树,下面的树对 1 号节点左旋后成为上面的树。 那么怎么做树旋转呢?这里给大家一句口诀(也是我从一些算法视频上学到的,并非原创):左旋拎右左挂右,右旋拎左右挂左。 什么意思呢?别急,等我细细道来。 2.2 右

Plozia 的小窝 2151

fast-lio系列改进版本

2.回环检测的优化结果,更新到FAST-LIO2的当前帧位姿中,幷进行ikdtree的重构,进而更新submap。其它的效果还不清楚,实测lio部分稳定性很好。用fast-lio_slam就很稳定。融合了fast-lio2和sc-pgo,两部分分开运行,SC-PGO从FAST-LIO2节点获取里程计和激光雷达点云主题。的作者kim在FAST-LIO2的基础上,添加SC-PGO模块,通过加入ScanContext全局描述子,进行回环修正,SC-PGO模块与FAST-LIO2解耦,非常方便,很优秀的工作。

z1872385的博客 3189

YOLO系列算法改进 | C3k2改进篇 | 融合DFRL双融合注意力接收层 | 轻量化与全局感受野双突破,适应高分辨率航拍与密集小目标检测场景 | CVPR 2026

YOLO系列算法改进 | C3k2改进篇 | 融合DFRL双融合注意力接收层 | 轻量化与全局感受野双突破,适应高分辨率航拍与密集小目标检测场景 | CVPR 2026 (以YOLO26最新目标检测模型为基础,利用C3k2_DFRL创新模块进行改进)

2502_91881744的博客 233

C++ AVL树(四种旋转,插入)

C++ AVL树(四种旋转,插入)

Wzs040810的博客 3513

笔试题-2023-紫光展锐-数字芯片设计【纯净题目版】

笔试题-2023-紫光展锐-数字芯片设计【纯净题目版】

w0shishabi的博客 2923

【C++】AVL树的插入、旋转

AVL树是高度平衡的二叉搜索树,相比普通的二叉搜索树,它防止了变成单支树的情况。因为AVL树每插入一个新的节点,它都会调整使左右子树的高度差的绝对值不超过1,从而降低了树的高度,提高了搜索效率。左右子树都是AVL树左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)搜索时间复杂度O(log2nlog_2 nlog2​n有平衡因子控制高度差:右子树高度减去左子树高度AVL树是三叉链结构,即左孩子指针、右孩子指针和双亲指针,多了一个双亲指针方便找到上一个节点。

2301_77459845的博客 1408

[RK3568 Android11] 开发之默认授予系统预置的APP权限

目录 一、系统预置的APP权限 二、默认授予系统预置的APP权限 一、系统预置的APP权限 1、在打开系统预置的APP时,都会弹窗提示,并且需要人工确定授予权限; 2、有些客户对定制有需求,需要系统预置的APP自动默认授予权限; 二、默认授予系统预置的APP权限 注意此方法只对系统预置的APP起效果,后期手动安装的APP无效; 修改文件: frameworks/base/services/core/java/com/android/server/pm/per...

~未来可期~ 5059

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

树的旋转和AVL树

AVL树是一种自平衡二叉搜索树,由. M. Adelson-Velsky和E. M. Landis,在他们1962年的论文《An algorithm for the organization of information》中发表。名声很大,就算自己没写过,也应该都听说过。这两天也是重新看了一下,记录一些理解。 1. AVL树简介 AVL树首先是一个二叉搜索树,然后AVL树中任何两个子树的高度差...

wx_14678的博客 431

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【AVL树】AVL树的插入操作以及旋转

在讲解AVL树之前必须了解二叉搜索树, 可以看我之前的博客:二叉搜索树AVL树是在二叉搜索树的基础上,在向二叉树排序树中插入新的结点,如果保证每个结点的左右子树的高度差的绝对值不超过1,即需要在插入的时候判断是否满足条件,然后对树进行旋转,从而可减低树的高度,减少平均搜索长度。AVL树:(1)它的左右子树都是AVL树 (2)右子树和左子树的高度差(平衡因子)的绝对值不能

菜鸟成长记 2695

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【C++】AVL树的旋转等

关于这几个旋转涉及到的结点,在命名时我们可以遵循一定的规律,最好不要随意命名。比如subL就是parent的左孩子的意思,L代表left;subLR就是subL的右孩子的意思。但是,我们的结点现在是三叉链的,所以_parent也要进行修改,而现在我们还没有改。这样还不对,因为subLR可能为空,其他两个则不可能。因为这种情况是h为0的情况。这样还是不行,因为如果parent的parent不为空,我们还没有将它的孩子结点更新为subL。

Octopus2077的博客 916

AVL树调整平衡及旋转详解

AVl树算是二叉搜索树的一种补充版,普通的二叉搜索树在最坏的情况下可以达到O(n)的时间复杂度,也就是歪脖子树。为了解决二叉搜索树的歪脖子现象,需要对插入的节点进行调整以达到相对平衡,这种经过调整的二叉搜索树叫二叉平衡树,而AVl树是平衡树的一种。AVl树总的来说就是所有节点的左右子树高度差不超过1所以AVL树有两个性质,第一必须满足二叉搜索树的规则,也就是所有节点的右边子树节点值都比根节点值大,左边节点值都比根节点值小。第二所以节点左右子树高度差(通常称为平衡因子)不超过1。

a1937194471的博客 1861

算法心经——AVL树旋转详解

AVL树旋转详解 AVL树是高度平衡的而二叉树。它的特点是:AVL树中任何节点的两个子树的高度最大差别为1,如下图所示。 下面我们直奔主题:如将一棵非AVL树转换为一棵AVL树。 在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图,每一种类型又对应两种情况,所以细分的话共有...

a1552100455的博客 857

AVL树的旋转操作(图解)

二叉搜索树的平衡–AVL树和树的旋转(图解) 二叉搜索树只有保持平衡时其查找效率才会高。 要保持二叉搜索树的平衡不是一件易事。不过还是有一些非常经典的办法可以做到,其中最好的方法就是将二叉搜索树实现为AVL树。 AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the or...

好热 1030

AVL树的旋转图解和简单实现

AVL树是带有平衡条件的查找二叉树。这个平衡条件要容易保持,而且他要保证树的深度为O(logN) 原文地址:http://blog.youkuaiyun.com/qq_25806863/article/details/74755131 平衡条件 一个最理想的平衡条件是左右两个子树的高度完全相等,但只有节点数量为2^n-1的树才满足这个条件(n是层数,2层要3个,3层要7个)。这个条件太严格,不好用。...

喵了个呜的博客 5万+
上一篇: AQS源码(一)之独占锁的获取
下一篇: JavaIO四大模型:NIO(IO多路复用)
Colourful.
博客等级 码龄6年 13粉丝 73原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值