AVL树的平衡算法的简化问题

server/2025/3/15 15:03:06/

AVL树是一种紧凑的二叉查找树。它的每个结点,都有左右子树高度相等,或者只相差1这样的特性。文章https://blog.csdn.net/aaasssdddd96/article/details/106291144给出了一个例子。

为了便于讨论,这里对AVL树的结点平衡情况定义2个名称,如果两边左右子树高度相等,称之为真平衡,如果两边高度相差1,称之为准平衡。真平衡和准平衡的这个意义只限于在本文的讨论。准平衡有2种情况,所以实际是3种情况。

AVL树中插入一个新结点时,它的父结点如果是真平衡,那么状态转化为准平衡,树的高度增加了1,因为高度增加,这个父结点需要接着向更高一层的父结点报告这个变化。

如果父结点是准平衡,那么也有2种情况。如果增加的高度是在较矮的一侧,那么父结点状态转为真平衡,操作完成;如果增加的高度是在较高的一侧,那么结点的平衡因子超限,这种情况在上面第一种情况的最后一个变化发生,需要进行平衡调整。调整之后,恢复为真平衡,局部高度不增,操作完成。

这些问题不难。真正让初学者感到烦恼的是平衡调整。调整分4种情况,分别称为“LL-旋转”,“LR-旋转”,“RL-旋转”,“RR-旋转”。后2种和前两种镜像对应。编写这部分代码的时候,最好写完前2种,休息20分钟,再去复制前面的代码,逐条改成它的镜像。休息片刻是为了避免头晕,转来转去转的头一晕,修改镜像时随便漏掉一条,就会带来极为费时难调的bug。这样编程并没有什么不对,这是需要掌握的基本功,而且实际开发过程也会常常碰到需要蛮力硬搞来攻克的难题。

但在这里是否有比硬搞好一点的办法?

如果在构造AVL树时,预分配3个储备结点会怎么样。左、中、右,预先结成一个三角形。但不在AVL树中,而是备用:

struct avl_help {struct node *root;struct triangle {struct node *left;struct node *mid;struct node *right;} help;
};struct avl_help avl;

初始化为:


avl.root=NULL;
avl.help.left = (struct node*)malloc(sizeof(struct node));
avl.help.mid = (struct node*)malloc(sizeof(struct node));
avl.help.right = (struct node*)malloc(sizeof(struct node));avl.help.mid->left=avl.help.left;
avl.help.mid->right=avl.help.right;
avl.help.left->parent=avl.help.mid;
avl.help.right->parent=avl.help.mid;

现在大家都想到了:在AVL树需要发生平衡调整的时候,把已经调好的3个储备结点拿出来,整体替换掉树中需要调整的3个结点,再把替换下来的原来的3个结点做成初始化中的左、中、右三角结构,存回到help中储备,留给下次用。这样调整就完成了。而替换下来的3个结点只要把头结点连到中间结点的左指针,或右指针,具体看那个指针空闲,就重新构成了三角结构。

以“LR型-旋转”为例,调整操作大致是这样子。假设ap0,ap1,ap2三个指针已经分别指向LR型的待调整的上中下3个结点:

help= &avl.help;
help->left->left=ap1->left;
help->left->right=ap2->left;
help->left->tag=(ap2->tag==1?0:-1);help->right->left=ap2->right;
help->right->right=ap0->right;
help->right->tag=(ap2->tag==-1?1:0);help->mid->tag=0;
if(help->left->left)
help->left->left->parent=help->left;
if(help->left->right)
help->left->right->parent=help->left;
if(help->right->left)
help->right->left->parent=help->right;
if(help->right->right)
help->right->right->parent=help->right;
help->mid->parent=ap0->parent;if(help->mid->parent==NULL)
avl->root= help->mid;
else if(help->mid->parent->left==ap0)
help->mid->parent->left=help->mid;
else help->mid->parent->right=help->mid;

而存回替换下来的ap0,ap1,ap2三个结点的代码就是:

ap1->left=ap0;
ap0->parent=ap1;
help->left= ap0;
help->mid=ap1;
help->right=ap2;

其它几种情况可以类推,大同小异,这里就不重复了。

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

相关文章

【新人系列】Golang 入门(四):集合类型 - 上

✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12898955.html 📣 专栏定位:为 0 基础刚入门 Golang 的小伙伴提供详细的讲解,也欢迎大佬们…

2025 比较靠谱的上位机软件开发公司有哪些

上位机作为连接硬件设备与用户操作的核心载体,开发上位机软件则需兼顾高效性、稳定性、可扩展性及行业适配性。从技术能力、服务保障到行业经验,不同企业在细分领域展现出独特优势。带大家了解下2025年比较靠谱且有核心竞争力的上位机软件开发公司有哪些…

Gemini 2.0 Flash 原生图像生成

Google Gemini 2.0 Flash 全新开放原生图像生成功能,为开发者带来了多模态输入、增强推理能力和自然语言理解的全新体验。 多模态输入支持 支持文字与图片的联合输入(如:上传产品图输入「将背景换成雪山场景」)实现精准的语义理…

谷歌Gemini 2.0 Flash重磅更新:图文融合,初现AGI曙光

Gemini再进化,多模态能力惊艳 谷歌Gemini模型一直以其强大的多模态能力著称。它是一个“水桶型”模型,各项能力均衡,尤其在多模态理解方面处于全球领先地位。近日,谷歌宣布在Google AI Studio和Gemini API上开放Gemini 2.0 Flash的…

微软 System Center Configuration Manager(SCCM)的组件文件

微软 System Center Configuration Manager(SCCM) 或 Microsoft Endpoint Configuration Manager(MECM) 的组件文件,属于企业级设备管理工具的一部分。以下是具体说明: C:\Windows\CCM\smsswd.exe C:\Windows\CCM\tsmanager.exe smsswd.exe 和 tsmanager.exe 是 Micros…

Python网络爬虫之BeautifulSoup库的使用流程和方法

在使用BeautifulSoup解析HTML或XML数据时,需要掌握其基本使用流程和常见方法。本节将详细介绍如何使用BeautifulSoup解析网页,包括加载HTML数据、查找元素、提取文本、获取属性以及遍历HTML结构,帮助读者掌握网页数据解析的核心技能。 1. 使用BeautifulSoup解析HTML数据 在…

编程自学指南:java程序设计开发,数组与集合,为什么需要数组和集合?数组的声明与初始化, 数组遍历,多维数组

编程自学指南:java程序设计开发,数组与集合 学习目标: 掌握数组的声明、初始化和遍历 理解集合框架(List、Set、Map)的核心区别与应用场景 能够使用集合解决实际数据存储与操作问题 避免数组越界和集合操作中的常见…

如何在Futter开发中做性能优化?

目录 1. 避免不必要的Widget重建 问题:频繁调用setState()导致整个Widget树重建。 优化策略: 2. 高效处理长列表 问题:ListView一次性加载所有子项导致内存暴涨。 优化策略: 3. 图片加载优化 问题:加载高分辨率…