平衡二叉树(AVL Tree)

转载至:https://www.cnblogs.com/jielongAI/p/9565776.html

在学习算法的过程中,二叉平衡树是一定会碰到的,这篇博文尽可能简明易懂的介绍下二叉树的相关概念,然后着重讲下什么事平衡二叉树。

(由于作图的时候忽略了箭头的问题,正常的树一般没有箭头,虽然不影响描述的过程,但是还是需要注意,所以还请读者忽略一下部分图的箭头)

一、二叉(查找)树

二叉查找树(Binary Search Tree)是二叉树的一种,其树节点(internal nodes of the tree)储存着键值并且满足以下特性并如图A所示:

  • 假设u, v, r分别为树的三个结点(nodes),r为树的根节点,u为根的左子树,v为根结点的右子树;
  • 键值大小关系:key(u) < key(r) < key(v),也就是位于根结点(亦或是父节点)的左子树的所有结点的值都是小于根或者父结点的,而位于右子树的结点都大于根或者父结点;
  • 树的外部结点不储存任何的信息。

图A 二叉查找树

二、二叉查找树的操作

2.1 查找(Search)

如若要查找二叉树中的某个元素k,我们会从根节点朝着树结构往下寻找对应的结点,所寻找的结点方向取决于当前结点与所要寻找的结点的值的对比。基于图A,假设我们现在所要寻找的结点是7,那么从根结点开始,我们可以知道7 < 8,那么往下朝着结点值为6的子树走,然后我们发现6 < 7所以此时我们就寻找结点为6的右子树,这时我们发现7 = 7,也就是到达了我们所要寻找的结点了,下图B是寻找结点的过程:

图B 二叉树查找过程

算法伪代码:

1
2
3
4
5
6
7
8
9
BSTreeSearch(k, v):
if T.isExternal(v):
    return v
elif k < key(v):
    return BSTreeSearch(k, T.left(v))
elif k == key(v):
    return v
else k > key(v):
    return BSTreeSearch(k, T.right(v))

2.2 插入(Insertion)

如果要执行插入操作,我们首先需要对树进行查找操作,找到相应的节点的叶子(leaf)结点,然后再执行插入操作。下面以插入5位例子进行执行,如果要插入5,执行2.1节中所说的二叉树的查找操作,我们可以发现5 < 8,5 < 6,5 > 4,这时我们可以发现最终5是大于4的,那么我们需要在4的右叶子结点插入5,并且延伸新插入的结点(5)的叶子结点。具体操作如下图C所示:

图C 二叉树插入操作

2.3 删除(Deletion)

相应的执行删除操作,我们也先需要查找到相对应的结点,然后将该结点从二叉树中移除(remove),实际代码实现中需要判断要删除的结点的键值是否存在于二叉树中,除此之外,如果该结点伴有叶子结点,那么需要将该结点和叶子结点一同移除。当然,这里亦有另外一种情况,就是被移除的结点的左右子树都是内部结点(internal nodes),这个时候的操作会稍微复杂一点,这里以删除4和6为例子来讲述这两种情况,具体的操作如图D(基于图C进行操作)所示:

图D 删除操作

删除结点4的操作相对简单,只需要移除该结点和相应的叶子节点即可,但是相反的删除6的时候,我们需要确保所有父结点的左子树都是小于该结点的,并且右子树都是大于该父结点的,所以当我们删除6的时候,我们需要将5移到相应的位置并在相应的叶子结点补上新的叶子。

2.4 算法表现(Performance)

假设一个二叉树的高度为H,最坏的操作情况是O(n),而最好执行情况则为O(log(n))。

三、二叉平衡树(AVL TREE)

3.1 平衡二叉树的定义

二叉平衡树指的是要么它本身是一个空树,要么它是一个左子树和右子树的深度之差的绝对值不大于1,并且保证左右子树都是平衡树,图E是一个平衡二叉树。从图中我们可以看出,一个结点的高度位1则表明为其叶子结点到父结点的高度,整颗树的高度取决于最深叶子结点到根结点的距离。

图E 平衡二叉树

3.2 平衡二叉树的操作

AVL树的查找操作和普通的二叉树的查找基本一致,但是插入和删除操作有所不同,因为插入和删除会减少树的结点并且改变树的结构,这个时候为了使树始终保持平衡状态我们需要对树进行重构使其始终保持平衡状态,一般这个操作叫做旋转操作(rotation),旋转分为左旋转和右旋转等,下面就具体来看看插入和删除操作及如何运用旋转使二叉平衡树在插入和删除某结点之后依然保持平衡。

3.2.1 旋转操作

在这个小节中主要介绍一下左旋转和右旋转,旋转操作不局限于这两个,但是基本原理都一样,最终目的就是为了让二叉平衡树在被操作之后再次达到平衡。

图F 左旋转

在上图所说的左旋转操作中,我们假设的是x < y < z,因为树不平衡了,我们执行左旋转,将x及其左子树进行左旋转,并且将原本y的左子树变为x的右子树,这里需要注意的两点,①就是我们需要寻找到三个点,这三个点的大小是有排序的,如这此段开头所说道的xyz的关系,将中间那个值作为新的中心结点,然后再进行旋转操作,②就是一定要确保所有的左右子树遵循二叉树的定义要求,既左子树一定要永远都是小于其父结点的,而右子树始终大于父结点的。

图G 右旋转

图G所述的三个节点的关系为z < x < y,因此根据左旋转所描述的我们可以知道x应该作为中心结点也就是父结点,然后这里需要进行两次旋转才能使二叉树最终处于平衡,首先是先对z进行左旋转,将z变为x的左子树,然后再对y进行右旋转,在这个过程中,x的左子树变为z的右子树,而右子树则成为了y的左子树。有了基本的这两个操作,接下来我们就根据实际例子来看看对平衡二叉树执行插入和删除的操作并且结合旋转来达到平衡状态。

3.2.2 插入操作

平衡二叉树的插入操作与普通二叉查找树的操作一样,新插入的节点都发生在叶子结点,唯一不同的就如上述所说,新插入的结点致使树的结构发生改变而导致不平衡,此时需要进行旋转以达到平衡。在图E的基础上插入一个新结点,结点的值为40,新得到的图如图H所示:

图H 插入新的节点Key(40)

这时我们会发现此时的二叉树已经不平衡,这时我们需要寻找到树里面导致树不平衡的三个点,进行相应的操作,具体有以下两步:① 先对结点39以结点42为父结点进行左旋转,此时节点40变成了39的右结点,而33,39,40一起成为了结点42的左子树。② 对结点53进行右旋转,将其变成节点42的右子树,结点55依然为结点53的右子树。由此便完成了整棵树的重构并让新的树保持平衡。重构之后的树如下图I所示:

图I 重构之后得到的树

3.2.3 删除操作

假设在图I的基础上删除结点22,那么此时我们从节点19开始便利找到第一个导致不平衡的结点为25并且具有最大高度值的结点,之后往右子树进行便利寻找到第二个具有最大高度值的结点,此结点为42(下图标注了红色边框的结点),

图J 删除之后进行重构流程图

3.2.4 二叉平衡树的算法表现

二叉平衡树的算法表现主要体现在以下几个方面:

  • 如果单独重构一次所需要的运行时间为O(1)
  • 如果查找二叉平衡树中某个结点的话为O(log(n))
  • 插入操作为O(log(n)),若需要重构,为了保持平衡所需要的时间为O(log(n))
  • 删除操作为O(log(n)),若需要重构,为了保持平衡所需要的时间为O(log(n))

以上便是有关二叉树和二叉平衡树相关的知识点,如果有哪里讲的不对的,还请读者指出,谢谢!

 

转载:平衡二叉树(AVL Tree)的更多相关文章

  1. 详解平衡二叉树(AVL tree)平衡操作(图+代码)

    * 左左就右旋,右右就左旋 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int max ...

  2. PAT A1123 Is It a Complete AVL Tree (30 分)——AVL平衡二叉树,完全二叉树

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  3. 平衡二叉树(AVL Tree)

    在学习算法的过程中,二叉平衡树是一定会碰到的,这篇博文尽可能简明易懂的介绍下二叉树的相关概念,然后着重讲下什么事平衡二叉树. (由于作图的时候忽略了箭头的问题,正常的树一般没有箭头,虽然不影响描述的过 ...

  4. PAT 甲级 1066 Root of AVL Tree (25 分)(快速掌握平衡二叉树的旋转,内含代码和注解)***

    1066 Root of AVL Tree (25 分)   An AVL tree is a self-balancing binary search tree. In an AVL tree, t ...

  5. 平衡二叉树AVL插入

    平衡二叉树(Balancedbinary tree)是由阿德尔森-维尔斯和兰迪斯(Adelson-Velskiiand Landis)于1962年首先提出的,所以又称为AVL树. 定义:平衡二叉树或为 ...

  6. 04-树5 Root of AVL Tree

    平衡二叉树 LL RR LR RL 注意画图理解法 An AVL tree is a self-balancing binary search tree. In an AVL tree, the he ...

  7. 数据结构与算法--从平衡二叉树(AVL)到红黑树

    数据结构与算法--从平衡二叉树(AVL)到红黑树 上节学习了二叉查找树.算法的性能取决于树的形状,而树的形状取决于插入键的顺序.在最好的情况下,n个结点的树是完全平衡的,如下图"最好情况&q ...

  8. A1123. Is It a Complete AVL Tree

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  9. 04-树5 Root of AVL Tree + AVL树操作集

    平衡二叉树-课程视频 An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the tw ...

随机推荐

  1. RFC3918聚合组播吞吐量测试——网络测试仪实操

    一.简介 1.RFC3918简介 历史 · 在1999年3月成为正式标准 功能 · 评测网络互连设备或网络系统的性能 · 网络设备: 交换机,路由器- 内容 · 定义了一整套测试方法,为不同厂家的设备 ...

  2. 从菜鸟到高手, HMS Core图像分割服务教你如何在复杂背景里精细抠图

    2021年以来,自动驾驶赛道进入爆发期,该行业成为大厂以及初创企业的必争之地.其中众多公司都采用了计算机视觉作为自动驾驶的技术底座,通过图像分割技术,汽车才能够有效理解道路场景,分清楚哪里是路,哪里是 ...

  3. 【C# 】继承

    背景..什么是继承? 「继承」是对象导向编程的其中一个基本属性. 它可让您定义子类,重复使用(继承).扩充或修改父类别行为. 其成员可供继承的类别称为基底类别. 继承基底类别成员的类别则称为「衍生类别 ...

  4. Windows操作下各种工具常用快捷键

    目录 Windows快捷键 谷歌浏览器快捷键 Nodepad++快捷键 Mobaxterm快捷键 Markdown快捷键 Windows快捷键 Win + E打开文件系统 Win + L锁屏 谷歌浏览 ...

  5. PyTorch深度学习实践-Overview

    Overview 1.PyTorch简介 ​ PyTorch是一个基于Torch的Python开源机器学习库,用于自然语言处理等应用程序.它主要由Facebookd的人工智能小组开发,不仅能够 实现强 ...

  6. TypeError

    1.only size-1 arrays can be converted to Python scalars 问题来源:需要把一个float数组A转为int,于是直接在代码中写了 B=int(A), ...

  7. ELK监控nginx日志总结

    ELK介绍 ELK即ElasticSearch + Logstash + kibana ES:作为存储引擎 Logstash:用来采集日志 Kibana可以将ES中的数据进行可视化,可以进行数据分析中 ...

  8. Python迭代器,生成器,装饰器

    迭代器 通常来讲从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值). 可迭代对象(iterable):是指该对象可以被 ...

  9. FaE:基于符号知识的适应性和可解释的神经记忆

    原创作者 | 朱林 论文解读: Facts as Experts: Adaptable and Interpretable Neural Memory over Symbolic Knowledge ...

  10. C#读写自定义的多字段配置文件

    mark一下,日后填坑 参考: WPF 读写自己写的配置文件