【数据结构与算法 | 二叉树篇】AVL树

news2024/11/24 13:44:51

1. 前言

AVL树是一种自平衡的二叉搜索树。为什么会出现AVL树。众所周知,虽然普通的二叉搜索树的平均时间复杂度为O(logn),但最差的情况的时间复杂度为O(n)。为了避免最差的这种情况,出现了AVL树。

我们规定:如果树有个节点它的左子树的高度-右子树的高度大于1或者它的右子树的高度-左子树的高度小于-1,我们就说该二叉搜索树是不平衡的,需要调整。

2. 四种失衡情况以及解决方案

简单聊聊AVL树相关的四种失衡情况:

  • (LL)某节点的左子树高度-右子树高度大于1,且失衡节点的左孩子也高于右孩子或等高;
  • (LR)某节点的左子树高度-右子树高度大于1,且其左孩子的左子树高度-右子树高度小于-1;
  • (RL)某节点的右子树高度-左子树高度大于1,且其右孩子的左子树高度-右子树高度大于1;
  • (RR)某节点的右子树高度-左子树高度大于1,且失衡节点的右孩子也高于左孩子或等高;

AVL树需要进行调整:

  • (LL)该节点需要右旋。
  • (LR)该节点的左孩子需要左旋,且该节点需要右旋。
  • (RL)该节点的右孩子需要右旋,且该节点需要左旋。
  • (RR)该节点需要左旋。

LL旋转情况如图:

LR旋转情况如图:

RL旋转情况如图:

RR旋转情况如图:

解决方法:

// 右旋(LL)
    private AVLNode RightRotation(AVLNode red) {
        AVLNode yellow = red.left;
        AVLNode blue = yellow.right;
        yellow.right = red;
        red.left = blue;
        // 更新red节点的高度
        updateHeight(red);
        // 再更新yellow节点的高度(因为red是yellow的孩子节点,
        // 只有计算对了red节点的高度,才会正确得出yellow节点的高度)
        updateHeight(yellow);
        return yellow;
    }
    // 左旋(RR)
    private AVLNode LeftRotation(AVLNode red){
        AVLNode yellow = red.right;
        AVLNode blue = yellow.left;
        yellow.left = red;
        red.left = blue;
        updateHeight(red);
        updateHeight(yellow);
        return yellow;
    }
    // (LR)
    private AVLNode LeftRightRotation(AVLNode node) {
        // 失衡节点的左孩子需要左旋
        node.left = LeftRotation(node.left);
        // 失衡节点需要右旋
        return RightRotation(node);
    }
    // (RL)
    private AVLNode RightLeftRotation(AVLNode node) {
        // 失衡节点的右孩子需要右旋
        node.right = RightRotation(node.right);
        // 失衡节点需要左旋
        return LeftRotation(node);
    }

3. AVL树代码

public class AVLTree {
    static private class AVLNode{
        int key;
        Object value;
        AVLNode left;
        AVLNode right;
        // 一个节点的默认高度为1
        int height = 1;

        public AVLNode(int key, Object value) {
            this.key = key;
            this.value = value;
        }

        public AVLNode(int key, Object value, AVLNode left, AVLNode right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }
    private int doHeight(AVLNode node){
        return node == null ? 0 : node.height;
    }
    private void updateHeight(AVLNode node) {
        if (node == null) {
            return;
        }
        node.height = Integer.max(doHeight(node.left), doHeight(node.right)) + 1;
    }
    // 平衡因子(balance factor),处于-1,0,1时是满足平衡的。
    private int bf(AVLNode node){
        return doHeight(node.left) - doHeight(node.right);
    }
    // 右旋(LL)
    private AVLNode RightRotation(AVLNode red) {
        AVLNode yellow = red.left;
        AVLNode blue = yellow.right;
        yellow.right = red;
        red.left = blue;
        // 更新red节点的高度
        updateHeight(red);
        // 再更新yellow节点的高度(因为red是yellow的孩子节点,
        // 只有计算对了red节点的高度,才会正确得出yellow节点的高度)
        updateHeight(yellow);
        return yellow;
    }
    // 左旋(RR)
    private AVLNode LeftRotation(AVLNode red){
        AVLNode yellow = red.right;
        AVLNode blue = yellow.left;
        yellow.left = red;
        red.left = blue;
        updateHeight(red);
        updateHeight(yellow);
        return yellow;
    }
    // (LR)
    private AVLNode LeftRightRotation(AVLNode node) {
        // 失衡节点的左孩子需要左旋
        node.left = LeftRotation(node.left);
        // 失衡节点需要右旋
        return RightRotation(node);
    }
    // (RL)
    private AVLNode RightLeftRotation(AVLNode node) {
        // 失衡节点的右孩子需要右旋
        node.right = RightRotation(node.right);
        // 失衡节点需要左旋
        return LeftRotation(node);
    }
    //检查节点是否失衡,重新平衡代码
    private AVLNode balance(AVLNode node) {
        if (node == null) return null;
        int bf = bf(node);
        if (bf > 1 && bf(node.left) >= 0){
            // LL
            return RightRotation(node);
        } else if (bf > 1 && bf(node.left) < 0) {
            return LeftRightRotation(node);
        } else if (bf < -1 && bf(node.right) > 0) {
            return RightLeftRotation(node);
        } else if (bf < -1 && bf(node.right) <= 0) {
            return LeftRotation(node);
        }
        // 进行到这,说明该节点不需要做平衡调整
        return node;
    }
    // 向AVL树添加节点,并保持平衡特性
    public void put(AVLNode node) {

    }
}

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

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

相关文章

大模型LLM——微调的七种方法

大模型的七种微调方法 文章目录 大模型的七种微调方法1. LoRA2. QLoRA3. 适配器调整4. 前缀调整5. 提示调整6. P-Tuning7. P-Tuning v2 1. LoRA LoRA的主要步骤包括&#xff1a; 选择微调目标权重矩阵&#xff1a;首先在大型模型&#xff08;如GPT&#xff09;中识别需要微调…

学习vue3 五,传送,缓存组件以及过渡和过渡列表

目录 Teleport传送组件 keep-alive缓存组件 transition动画组件 1. 过渡的类名 2. 自定义过渡class名 3. transition的生命周期 4.appear transition-group 1. 过渡列表 2. 列表的移动过渡 3. 状态过渡 Teleport传送组件 Teleport Vue 3.0新特性之一。 Teleport 是一…

AI技术如何重塑企业EHS安全健康环保体系,附实践案例

随着人工智能技术的快速发展&#xff0c;其在环境、健康和安全&#xff08;EHS&#xff09;管理领域的应用日益广泛。AI技术通过大数据分析、模式识别和预测建模等手段&#xff0c;为EHS管理提供了新的视角和工具。这一变革不仅提升了风险评估和事故预防的效率&#xff0c;同时…

Can‘t use Subversion command line client:svn不能使用Subversion命令行客户端:svn

1、导入idea中会报Can’t use Subversion command line client… 2、在提交svn代码的时候&#xff0c;出现这样的错误&#xff1a;Can’t use Subversion command line client: svn Probably the path to Subversion executable is wrong. Fix it. 问题原因&#xff1a;在安…

实验8-1-4 拆分实数的整数与小数部分

本题要求实现一个拆分实数的整数与小数部分的简单函数。 函数接口定义&#xff1a; void splitfloat( float x, int *intpart, float *fracpart );其中x是被拆分的实数&#xff08;0≤x<10000&#xff09;&#xff0c;intpart和fracpart分别是将实数x拆分出来的整数部分与…

sqli-labs1-24通关教程

目录 前置知识 第一关 1、第一关是单引号字符型注入,输入id1‘会报错 2、输入注释符正常显示 3、爆出列数为联合做准备 4、使用联合查询爆出数据库名 5、使用information_schema爆出表名 6、猜测用户名再users表中&#xff0c;爆出列名 ​编辑 7、利用查出来的表名数据…

【第2期】2024 搜索客 Meetup | Elasticsearch 的代码结构和写入查询流程的解读

本次活动由 搜索客社区、极限科技&#xff08;INFINI Labs&#xff09;联合举办&#xff0c;活动主题将深入探讨 Elasticsearch 的两个核心方面&#xff1a;代码结构以及写入和查询的关键流程。本次活动将为 Elasticsearch 初学者和有经验的用户提供宝贵的见解&#xff0c;欢迎…

叉车(工业车辆)安全监控管理系统,叉车安全方案

叉车作为特种设备的一种&#xff0c;存在一定的危险性&#xff0c;操作过程出现意外的情况可谓是不胜枚举&#xff0c;轻则伤财、受些皮外伤&#xff0c;重则直接致人死亡。为加强叉车操作的安全管理&#xff0c;从2023年12月1日起实施的TSG 81-2022《场&#xff08;厂&#xf…

【网络安全学习】SQL注入02:使用sqlmap进行注入

1.sqlmap的基本功能 sqlmap的基本功能是对Web应用中的数据库进行自动化的检测、利用和攻击。 使用pikachu靶场进行sqlmap的基础功能使用。 1️⃣ 第一步&#xff1a;先检查是否有注入点&#xff1a; # -u : 指定目标url&#xff0c;也就是指定注入点 sqlmap -u "http:…

终端命令行|CLI工具|CMD|PowerShell

基本概念 终端是一个文本界面&#xff0c;用于执行基于文本的程序。 果你正在运行任何用于 web 开发的工具&#xff0c;你一定需要打开命令行并运行一些命令来使用你所选择的工具 (这样的工具被称为CLI 工具也就是命令行接口工具)。 命令行接口工具 (CLI 工具) 是什么&#xf…

延伸--人工鱼群算法

目录 基本原理 改进策略 代码示例 应用实例 总结 人工鱼群算法在解决多峰函数问题中的具体应用案例和效果如何&#xff1f; 双群人工鱼群算法与传统人工鱼群算法相比&#xff0c;有哪些具体的改进和优势&#xff1f; 步长自适应调整在人工鱼群算法中的实现机制是什么&a…

vue3踩坑问题记录

//vue3element-plus //1、placeholder换行显示 const startTxt ref() const contentText ref<any>() startTxt.value "请描述问题内容、例如&#xff1a;" historyData.prompt.forEach((el:any)>{contentText.value \n${el.question}}) <ElInputv-mo…

点赞收藏测试文章(让我看看有多少机器人在刷互动量)

前言 这里有一些看似合理但实际毫无意义的句子&#xff0c;我需要用它来看看跟我互动的有多少机器人 如果你是人类用户&#xff0c;可以用评论来代替点赞&收藏&#xff0c;爱你~ 目录 前言 正文 1. 紫色的大象在夜空中游泳。 2. 月亮上的饼干师烤出了一片海洋。 3. 时…

数据结构(邓俊辉)学习笔记】词典 03—— 排解冲突(1)

文章目录 1. 一山二虎2. 泾渭分明3. 开放定址4. 线性试探5. 赖惰删除 1. 一山二虎 此前我们已经多次指出&#xff0c;对于需要动态维护的散列表冲突是不可避免的&#xff0c;无论你的散列函数设计的有多么精妙&#xff0c;因此我们不得不回答的第二个重要问题就是一旦发生冲突&…

苹果电脑维护工具:CleanMyMac X让你的Mac焕发新生!

在我们的数字生活中&#xff0c;苹果电脑&#xff08;Mac&#xff09;已成为不可或缺的一部分&#xff0c;无论是为工作披星戴月&#xff0c;还是为娱乐畅游云端。但是&#xff0c;就像任何长时间运行的机器一样&#xff0c;Mac也可能会因为积累的文件和不必要的数据而开始变慢…

DAMA学习笔记(十一)-元数据管理

1.引言 元数据最常见的定义是“关于数据的数据”。它描述了数据本身&#xff08;如数据库、数据元素、数据模型&#xff09;&#xff0c;数据表示的概念&#xff08;如业务流程、应用系统、软件代码、技术基础设施&#xff09;&#xff0c;数据与概念之间的联系&#xff08;关系…

60页PPT数据湖 + 数据中台实施方案

关注智慧方案文库&#xff0c;学习8700多份智慧城市&#xff0c;智慧医院&#xff0c;智能制造&#xff0c;数字化转型&#xff0c;新质生产力&#xff0c;算力&#xff0c;大模型&#xff0c;AIGC&#xff0c;工业互联网&#xff0c;数字孪生......持续更新热点行业解决方案。…

.NET C# Dictionary Hashtable

.NET C# Dictionary & Hashtable 文章目录 .NET C# Dictionary & Hashtable1 Dictionary1.1 底层实现1.2 优点1.3 缺点 2 Hashtable2.1 底层实现2.2 优点2.3 缺点 3 对比总结4 遍历方式&#xff0c;与耗时对比foreach遍历Keys遍历IDictionaryEnumerator遍历耗时对比 1 …

自动化报表实践小结

这一天午休刚休息完&#xff0c;财务经理就喊我&#xff1a;“***&#xff0c;我们找个会议室聊聊”。我是一脸茫然&#xff0c;心里想着&#xff0c;我跟他也没什么私下的工作交流啊&#xff0c;能聊啥呢&#xff0c;还要找个会议室&#xff1f;究竟是什么事情呢&#xff1f;有…

VsCode无法远程调试

一、问题描述 按照《VsCode gdb gdbserver远程调试C程序》中介绍的方法&#xff0c;配置好VsCode后&#xff0c;按下F5快捷键&#xff0c;或点击“Start Debugging”按钮&#xff0c;没有反应&#xff0c;无法启动调试&#xff1a; 二、解决方法 针对该问题&#xff0c;我尝…