当前位置: 首页 > news >正文

手写数据结构-- avl树

1. 介绍

avl树是一种平衡二叉树,对于我来说手写这个树还是有一定难度的。

去年其实写过一次,但是只关注了旋转的部分而且也没有写博客记录。

于是今年重新写了一遍,发现之前的实现对于失衡情况的处理有问题。

之前对于失衡情况只处理了一次,正确的实现应该从当前节点开始一直

往父节点回溯,直到当前节点的子树重新平衡为止。

2. 旋转类型

avl是通过维护两子树高度差不超过1来保证不会出现退化的,比如说传统的二叉排序树对于有序插入1 2 3 4 5 6 这样的情况,会直接退化成链表的。

avl树发生失衡时,就通过旋转来进行调整。

一共有四种旋转类型,不过最基础的只有两种:左旋、右旋;

剩余的旋转类型只是复合一下这两种类型:

左右旋转,就是先左旋,再右旋转。
右左旋转,就是先右旋,再左旋转。

2.1 左旋

这种情况发生在右子树高度比左子树高2,且右子树的右子树高度+1

等于右子树高度。

直接偷programiz的图来说明

在这里插入图片描述

如上图所示,假设用绝对值来表示树的高度,那么发生左旋的情况就是

∣y∣−∣α∣=2∣γ∣−∣α∣=1|y|-|\alpha|=2\\ |\gamma|-|\alpha|=1 yα=2γα=1

至于β\betaβ的高度我们并不关心。

由于我们想让高度回落,因此新的树根就不能再为xxx

而是要让yyy变成新的根。

那么xxx和它的子树α\alphaα就变成了yyy的左子树,

yyy原来的左子树β\betaβ怎么办呢,由于β\betaβ肯定比xxx大,

所以让它链接在xxx的右子树上好了。

旋转后的树长下面这样,中间先后顺序的细节自己试一下就知道了。

我也不想写那么细了。

在这里插入图片描述

2.2 右旋

右旋就类似了,左子树的高度比右子树的高度大2。

左子树的左子树高度加一为左子树高度。

还是看图吧!

在这里插入图片描述

同样的表示法

∣x∣−∣α∣=2∣x∣=∣γ∣+1|x|-|\alpha|=2\\ |x|=|\gamma|+1 xα=2x=γ+1
至于β\betaβ子树的高度,我们不关心。

由于我们想让高度回落,因此新的树根就不能再为yyy

而是要让xxx变成新的根。

那么yyy和它的子树α\alphaα就变成了xxx的右子树,

xxx原来的右子树β\betaβ怎么办呢,由于β\betaβ肯定比xxx小,

所以让它链接在xxx的左子树上好了。

旋转后的树

在这里插入图片描述

2.3 左右旋

这种情况发生在左子树高度比右子树高度高222

且左子树的右子树高度+1等于左子树的高度。

注意这种情况实际上是左子树失衡的另外一种情况,

只有它不是左旋的情况时,才考虑这种情况。

在这里插入图片描述
如图所示,左右旋的情况需要满足

∣x∣−∣δ∣=2∣y∣−∣δ∣=1∣α∣=∣δ∣|x|-|\delta| =2\\ |y|-|\delta|=1\\ |\alpha|=|\delta| xδ=2yδ=1α=δ

先对xyxyxy进行左旋,再对yz右旋。

在这里插入图片描述

2.4 右左旋

这种情况发生在右子树高度比左子树高度高222

且右子树的左子树高度+1等于右子树的高度。

注意这种情况实际上是右子树失衡的另外一种情况,

只有它不是右旋的情况时,才考虑这种情况。

在这里插入图片描述
如图所示,右左旋的情况需要满足

∣x∣−∣f∣=2∣y∣+1=∣x∣∣α∣=∣f∣|x| - |f|=2\\ |y|+1=|x|\\ |\alpha|=|f| xf=2y+1=xα=f

先对xyxyxy右旋转,再对yzyzyz左旋转。

在这里插入图片描述

3. 删除一个节点

删除节点的实现感觉不太统一,我这里的实现是用的替换。

先找到替换的节点,

要么是左子树的最右节点,要么是右子树的最左节点。

其实就是中序遍历的前一个或者后一个节点罢了。

在完成值替换后,找到被替换节点父节点,将被替换的节点从树上

删除掉,再从这个父节点开始判断是否失衡并调整一直到根。

这里我们需要一直调整了,因为删除一个节点导致的树高度回落

有可能导致一连串的失衡!

比如说下面的情况,删除了一个节点但连续调整了两次。

在这里插入图片描述
删除节点10后

在这里插入图片描述
第一次调整后

在这里插入图片描述
第二次调整
在这里插入图片描述

在这里插入图片描述

4. 插入一个节点

对于每个节点, 我们需要维护下面的值

struct avl_node_ {int height;int val;struct avl_node_ *lchild;struct avl_node_ *rchild;struct avl_node_ *parent;
};

插入的算法其实跟普通的二叉搜索树的插入完全一样,只不过在插入后

我们树可能失衡,我们就需要重新平衡子树。

我们在插入完成后,判断插入节点的父亲节点对对应的树是否发生了

失衡,如果失衡了就判断失衡的类型,从而决定旋转的类型来调整。

插入引起的高度最多是增加一,因此一次调整就可以使得树平衡了。

但为了省事其实可以沿用一直调整到树平衡这个函数。

5. 代码实现

放在我的gitee上了。

可以年看下参考里的第二个,它是有动画演示的。

6. 参考

prograiz
usfca

http://www.dtcms.com/a/403915.html

相关文章:

  • MySQL-事务日志
  • SpringBoot旅游管理系统
  • 永州市城乡建设规划局网站湖南大型网站建设公司
  • 买东西网站有哪些汽车设计公司排名前十强
  • IT 疑难杂症诊疗室:破解常见故障的实战指南​
  • 集团网站建设详细策划广告设计与制作模板
  • OSError: [WinError 182] 操作系统无法运行 %1。 解决办法
  • 部门网站建设的工作领导小组局域网建设简单的影视网站
  • 嵌入式学习(45)-基于STM32F407Hal库的Modbus Slave从机程序
  • 【字符串算法集合】KMP EXKMP Manacher Trie 树 AC 自动机
  • 网站是哪家公司开发的中山网站建设文化价位
  • 织梦网站如何备份教程企业网站建设公司网络
  • 杭州的网站建设公司4s店网站建设方案
  • 如果在自己电脑上运行,没有问题。但是移植到工控机,有问题
  • 网站建设计划方案中国著名的个人网站
  • 漫谈<爬虫与反爬的斗争>之反爬技术全景综述
  • @WebFilter 过滤器的执行顺序
  • 唐山建站方案七台河新闻综合频道直播
  • webpack library
  • 网站如何做背景音乐苏州集团网站建设
  • 建设工程招聘信息网站微信pc版
  • windows系统怎么做ppt下载网站永康外贸网站建设
  • 人工设计图像特征
  • 网站抓取qqwordpress 菜单 导航
  • centos网卡设置问题
  • springboot 自定义注解记录接口访问日志表
  • 在JavaScript中,每句结尾是否加分号
  • 申请免费网站公司wordpress+任意下载
  • 建立网站的条件网站建设拾金手指下拉二一
  • MS1100甲醛传感器详解(STM32)