【数据结构 -- AVL树】用golang实现AVL树

目录

  • 引言
  • 定义
  • 旋转方式
    • LL型
    • RR型
    • LR型
    • RL型
  • 实现
    • 结构
    • 获取结点高度
    • 平衡因子
    • 更新高度
    • 左旋
    • 右旋
    • 插入结点
    • 中序遍历

引言

AVL树,基于二叉搜索树通过平衡得到

前面我们知道,通过🔗二叉搜索树可以便捷快速地查找到数据,但是当序列有序时,就会退化成如下图所示的单链表,搜索效率降低为O(N),为了解决这个问题,引出了平衡二叉树(AVL树)

在这里插入图片描述

定义

平衡二叉树,简称AVL树,它可以是一颗空树
如果不是空树,则需要满足 任何一个结点的左子树与右子树高度之差的绝对值不超过1

在这里插入图片描述

图一是AVL树
图二不是AVL树,因为虚线内部分高度差大于1

如何让二叉树变成AVL树呢
答案是通过旋转(左旋、右旋)操作,在说左旋和右旋操作之前,了解一个概念——平衡因子

是否为AVL树需要根据结点的左右子树高度差来判断,所以引出平衡因子的概念
平衡因子:结点左子树高度减去右子树高度
之后我们还可以通过平衡因子来判断需要哪种旋转方式(左旋、右旋)

将二叉树分为四种类型,分别是LL(left)型、RR(right)型、
LR型、RL型
这几种类型是根据引起不平衡的结点的位置来分的,下面将引起不平衡的这个结点叫做unbalanceNode

旋转方式

判断右旋还是左旋,可以这样理解
向哪个方向旋转就是让哪边树更高。比如左旋,就是右子树高于左子树,要想平衡就要让左子树更高一点

LL型

unbalanceNode在根结点左孩子的左子树 – 根结点右旋

如图,插入结点5后导致二叉树失衡,插入的结点5在根结点左孩子14的左子树上,所以就是 LL 型

在这里插入图片描述

LL型二叉树的平衡因子满足:
根结点:2
根结点的左孩子:1(左孩子的左子树高度>右子树)

方法就是将根结点右旋,意思就是将根结点向右旋转到其左孩子的右孩子的位置

在这里插入图片描述

在根结点向右旋转的过程中,因为根结点的左孩子14原本有右孩子20,所以根结点就会和20发生冲突,这时需要将14的右孩子20变成根结点的左孩子

根结点25旋转完成后就是

在这里插入图片描述

再和14相连,最终结果:

在这里插入图片描述


如果出现了多个结点都失衡的情况,如下图
在这里插入图片描述

46、35、24都失衡了,那这时候就不是将根结点右旋了,而是将 与导致失衡的结点(15)最近的失衡结点右旋,在这个例子中也就是将24右旋
在这里插入图片描述

再与35相连,最终结果:
在这里插入图片描述


RR型

unbalanceNode在根结点右孩子的右子树 – 根结点左旋

RR 型与 LL 型方法一致,只是换汤不换药

如图,插入结点67后导致二叉树失衡,插入的结点67在根结点右孩子45的右子树上,所以就是 RR 型

在这里插入图片描述

RR型二叉树的平衡因子满足:
根结点:-2
根结点的左孩子:-1(左孩子的右子树高度>左子树)

方法就是将根结点左旋,意思就是将根结点向左旋转到其右孩子的左孩子的位置
在这里插入图片描述

在根结点向左旋转的过程中,因为根结点的右孩子45原本有左孩子34,所以根结点就会和34发生冲突,这时需要将45的左孩子34变成根结点的右孩子

根结点26旋转完成后就是
在这里插入图片描述

再和45相连,最终结果:
在这里插入图片描述


如果同时出现了多个失衡结点,和 LL 型一样,也是找到与导致失衡结点距离最近的失衡的结点,对该结点进行左旋操作


LR型

unbalanceNode在根结点左孩子的右子树 – 先左旋再右旋(根结点的左孩子左旋,根结点右旋)

如图,插入结点40后导致二叉树失衡,插入的结点40在根结点左孩子25的右子树上,所以就是 LR 型
在这里插入图片描述

LR型的平衡因子满足:
根结点:2
根结点的左孩子:-1(左孩子的右子树高度>左子树)

方法就是

  1. 先将根结点的左孩子左旋
  2. 再将根结点右旋

对于这个二叉树,调整过程:

  1. 将根结点的左孩子左旋
    在这里插入图片描述
  2. 将根结点右旋后
    在这里插入图片描述

RL型

unbalanceNode在根结点右孩子的左子树 – 先右旋再左旋(根结点的右孩子右旋,根结点左旋)

如图,插入结点29后导致二叉树失衡,插入的结点29在根结点右孩子48的左子树上,所以就是 RL 型
在这里插入图片描述

LR型的平衡因子满足:
根结点:-2
根结点的右孩子:1(右孩子的左子树高度>右子树)

方法就是

  1. 先将根结点的右孩子右旋
  2. 再将根结点左旋

对于这个二叉树,调整过程:

  1. 将根结点的右孩子右旋
    在这里插入图片描述

  2. 将根结点左旋
    在这里插入图片描述

实现

结构

结构体中一定包含的是数据data 和左右孩子指针
又因为需要计算平衡因子,所以需要知道左右子树的高度,直接将高度height 包含在结构体中

// 定义树结构
type BTNode struct {data   int //数据left   *BTNoderight  *BTNodeheight int //树的高度
}

获取结点高度

首先判断结点 t 为不为 nil, 为 nil 直接返回0

// 获取结点高度
func (t *BTNode) GetHeight() int {if t == nil {return 0}return t.height
}

平衡因子

平衡因子 = 左子树高度 - 右子树高度
若结点 t 为 nil ,直接返回0

// 计算结点的平衡因子 -- 左子树高度-右子树高度
func (t *BTNode) GetBalanceFactor() int {if t == nil {return 0}return t.left.GetHeight() - t.right.GetHeight()
}

更新高度

在插入或删除数据后,根结点和其他结点的高度都有可能发生变化,所以在插入或删除结点后,需要更新节点的高度,否则在计算平衡因子会出错

// 更新高度
func (t *BTNode) UpdateHeight() {leftHeight := t.left.GetHeight()rightHeight := t.right.GetHeight()if leftHeight > rightHeight {t.height = leftHeight + 1} else {t.height = rightHeight + 1}
}

左旋

对 node 进行左旋 --> node连接在node.right 的左孩子,如果node.right 原本有左孩子leftChild,那让leftChild 连接到node 的右孩子

// 左旋
func (t *BTNode) LeftRotate() *BTNode {//新的根结点变为t的右孩子newT := t.right//判断newT有没有左孩子if newT.left == nil{  //newT原本没有左孩子,t为newt.T左孩子newT.left = t}else { //newT原本有左孩子,原本的左孩子变为t的右孩子,t为newT左孩子t.right = newT.leftnewT.left = t}//更新高度t.UpdateHeight()newT.UpdateHeight()return newT
}

对上面的代码,还可以再简化
如果newT没有左孩子,即为nil,也可以直接赋值给t.right

// 左旋
func (t *BTNode) LeftRotate() *BTNode {//新的根结点变为t的右孩子newT := t.rightt.right = newT.leftnewT.left = t//更新高度t.UpdateHeight()newT.UpdateHeight()return newT
}

右旋

对 node 进行右旋 --> node连接在node.left 的右孩子,如果node.left 原本有右孩子rightChild,那让rightChild 连接到node 的左孩子

// 右旋
func (t *BTNode) RightRotate() *BTNode {newT := t.leftt.left = newT.rightnewT.right = tt.UpdateHeight()newT.UpdateHeight()return newT
}

插入结点

按照二叉搜索树插入数据的方式插入,再根据平衡因子判断是否需要调整和调整的方式

// 插入结点
func (t *BTNode) Insert(data int) *BTNode {if t == nil {return &BTNode{data,nil,nil,1,}}//递归查找插入位置if data < t.data {t.left = t.left.Insert(data)} else if data > t.data {t.right = t.right.Insert(data)} else {return t //不支持重复数据}//更新当前结点的高度t.UpdateHeight()//检查是否需要旋转balance := t.GetBalanceFactor()//左子树高if balance > 1 {if t.left.GetHeight() == 1 { //左孩子的左子树高 -- ll型//右旋return t.RightRotate()}if t.left.GetHeight() == -1 { //左孩子的右子树高 -- lr型//先对左孩子左旋,再对结点右旋t.left.LeftRotate()return t.RightRotate()}}//右子树高if balance < -1 {if t.right.GetHeight() == 1 { //右孩子的右子树高 -- rr型return t.LeftRotate()}if t.right.GetHeight() == -1 { //右孩子的左子树高 -- rl型先对右孩子右旋,再对结点左旋t.right.RightRotate()return t.LeftRotate()}}return t
}

中序遍历

// 中序遍历
func (t *BTNode) InOrder() {if t == nil {return}t.left.InOrder()fmt.Printf("%d ", t.data)t.right.InOrder()
}

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

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

相关文章

PyTorch图像识别模型和图像分割模型体验

文章目录 仓库地址练习&#xff1a;图像自动识别模型数据集说明模型训练和保存导入数据集搭建神经网络训练和保存实现 模型测试测试代码测试结果 练习&#xff1a;图像自动分割模型模型训练和保存加载数据集搭建神经网络训练和保存 模型测试测试代码测试效果 仓库地址 图像识别…

威纶通触摸屏IP地址设定步骤及程序下载指南

在使用威纶通触摸屏时&#xff0c;正确设定IP地址以及完成程序下载是确保其正常运行和实现功能的关键步骤。本文将详细介绍威纶通触摸屏IP地址设定步骤及程序下载的方法。 一、IP地址设定步骤 &#xff08;一&#xff09;前期准备 确保威纶通触摸屏已经通电并启动&#xff0…

一文读懂|大模型智能体互操作协议:MCP/ACP/A2A/ANP

导读 随着推理大模型的出现&#xff08;deepseek&#xff0c;Qwen3等&#xff09;&#xff0c;进一步地推进了大模型的智能体系统发展。然而&#xff0c;如何使智能体更好的调用外部工具&#xff0c;智能体与智能体之间如何有机地协作&#xff0c;仍然没有一个完美的答案。这篇…

前端下载ZIP包方法总结

在前端实现下载 ZIP 包到本地&#xff0c;通常有以下几种方法&#xff0c;具体取决于 ZIP 包的来源&#xff08;静态文件、后端生成、前端动态生成等&#xff09;&#xff1a; 方法 1&#xff1a;直接下载静态文件&#xff08;最简单&#xff09; 如果 ZIP 包是服务器上的静态…

简单使用Slidev和PPTist

简单使用Slidev和PPTist 1 简介 前端PPT制作有很多优秀的工具包&#xff0c;例如&#xff1a;Slidev、revealjs、PPTist等&#xff0c;Slidev对Markdown格式支持较好&#xff0c;适合与大模型结合使用&#xff0c;选哟二次封装&#xff1b;revealjs适合做数据切换&#xff0c…

数据挖掘:从数据堆里“淘金”,你的数据价值被挖掘了吗?

数据挖掘&#xff1a;从数据堆里“淘金”&#xff0c;你的数据价值被挖掘了吗&#xff1f; 在这个数据爆炸的时代&#xff0c;我们每天都在产生海量信息&#xff1a;社交媒体上的点赞、网购时的浏览记录&#xff0c;甚至是健身手环记录下的步数。这些数据本身可能看似杂乱无章…

程序运行报错分析文档

zryhuawei:~/src/modules/Connect$ ./newbuild/OpConnectAidTool \WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version. replace into process_tracking (step_id,date,status,context_data,start_time,end_time,error_log) values(?,?,?…

基于flask+vue的电影可视化与智能推荐系统

基于flaskvue爬虫的电影数据的智能推荐与可视化系统&#xff0c;能展示电影评分、评论情感分析等直观的数据可视化图表&#xff0c;还能通过协同过滤算法为用户提供个性化电影推荐&#xff0c;帮助用户发现更多感兴趣的电影作品&#xff0c;具体界面如图所示。 本系统主要技术架…

BYUCTF 2025

几周没会的比赛了&#xff0c;都是一题游。这周的BYU还不错&#xff0c;难度适中&#xff0c;只是时间有点短。周末时间不够。 Crypto Many Primes from Crypto.Util.number import bytes_to_long, getPrime import randomflag open("flag.txt").read().encode()…

链表的面试题8之环形链表

许久不见&#xff0c;那么这是最后倒数第三题了&#xff0c;这道题我们来看一下环形链表。 老规矩贴链接&#xff1a;141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 目录 倒数第k个元素 获取中间元素的问题。 双指针 来&#xff0c;大致看一下题目&#xff0c;这…

在 JavaScript 中正确使用 Elasticsearch,第二部分

作者&#xff1a;来自 Elastic Jeffrey Rengifo 回顾生产环境中的最佳实践&#xff0c;并讲解如何在无服务器环境中运行 Elasticsearch Node.js 客户端。 想获得 Elastic 认证&#xff1f;查看下一期 Elasticsearch Engineer 培训的时间&#xff01; Elasticsearch 拥有大量新…

2025年网站安全防御全解析:应对DDoS与CC攻击的智能策略

2025年&#xff0c;随着AI技术与物联网设备的深度融合&#xff0c;DDoS与CC攻击的规模与复杂度持续升级。攻击者不仅利用T级流量洪泛冲击带宽&#xff0c;还通过生成式AI伪造用户行为&#xff0c;绕过传统防御规则。如何在保障业务高可用的同时抵御混合型攻击&#xff1f;本文将…

window 安装 wsl + cuda + Docker

WSL 部分参考这里安装&#xff1a; Windows安装WSL2 Ubuntu环境 - 知乎 如果出现错误&#xff1a; WslRegisterDistribution failed with error: 0x800701bc 需要运行&#xff1a;https://crayon-shin-chan.blog.csdn.net/article/details/122994190 wsl --update wsl --shu…

《MambaLLIE:基于隐式Retinex感知的低光照增强框架与全局-局部状态空间建模》学习笔记

Paper:2405.16105 Github:GitHub - wengjiangwei/MambaLLIE 目录 摘要 一、介绍 二、相关工作 2.1 低光图像增强 2.2 视觉空间状态模型 三、方法 3.1 预备知识 3.2 整体流程 3.3 全局优先-局部次之状态空间块 四、实验 4.1 基准数据集与实施细节 4.2 对比实验 4…

微信小程序:封装request请求、解决请求路径问题

一、创建文件 1、创建请求文件 创建工具类文件request.js,目的是用于发送请求 二、js接口封装 1、写入接口路径 创建一个变量BASE_URL专门存储api请求地址 2、获取全局的token变量 从缓存中取出token的数据 3、执行请求 (1)方法中接收传递的参数 function request(url,…

【单机版OCR】清华TH-OCR v9.0免费版

今天向大家介绍一款非常好用的单机版OCR图文识别软件&#xff0c;它不仅功能多&#xff0c;识别能力强&#xff0c;而且还是免费使用的。OCR软件为什么要使用单机版&#xff0c;懂得都懂&#xff0c;因为如果使用在线识别的OCR软件&#xff0c;用户需要将文档上传互联网服务器的…

开源情报搜集系统:科研创新的强大引擎

一、引言 在当今全球化和信息化高度发展的时代&#xff0c;科研活动面临着前所未有的机遇与挑战。一方面&#xff0c;知识的更新换代速度极快&#xff0c;科研成果如雨后春笋般不断涌现&#xff1b;另一方面&#xff0c;科研竞争日益激烈&#xff0c;如何在众多科研团队中脱颖…

产品生命周期不同阶段的营销策略

产品生命周期的不同阶段&#xff08;导入期、成长期、成熟期、衰退期&#xff09;需要匹配差异化的营销策略。以下是各阶段的营销重点及具体策略&#xff1a; 1. 导入期&#xff08;Introduction Stage&#xff09; 核心目标&#xff1a;建立市场认知&#xff0c;快速触达目标…

Mujoco 学习系列(二)基础功能与xml使用

这篇文章是 Mujoco 学习系列第二篇&#xff0c;主要介绍一些基础功能与 xmI 使用&#xff0c;重点在于如何编写与读懂 xml 文件。 运行这篇博客前请先确保正确安装 Mujoco 并通过了基本功能与GUI的验证&#xff0c;即至少完整下面这个博客的 第二章节 内容&#xff1a; Mujoc…

面向SDV的在环测试深度解析——仿真中间件SIL KIT应用篇

1.引言 在汽车行业向软件定义汽车&#xff08;SDV&#xff09;转型的过程中&#xff0c;传统硬件在环&#xff08;HIL&#xff09;测试方案因难以适应新的技术架构与需求&#xff0c;其局限性日益凸显。传统HIL对硬件依赖性强&#xff0c;扩展性差&#xff0c;更换ECU或传感器…