平衡二叉树(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. Burp suite基本配置介绍

    实验目的 利用Burp Spider功能探测目标网站的目录结构. 实验原理 1)Burp Suite是Web应用程序测试的最佳工具之一,其多种功能可以帮我们执行各种任务.请求的拦截和修改,扫描web应 ...

  2. Smartbi:利用好excel分析工具,数据分析都是小case!

    数据分析听起来好像很高端的样子,但是实际上在一些IT高手的眼里,只需要掌握以下几个excel数据分析小工具的使用,你也能够成为别人眼中的数据大神! 1.excel数据分析工具--条件格式 快速找出符合 ...

  3. Zabbix 5.0:服务端进程总结

    Blog:博客园 个人 参考:<深入理解Zabbix监控系统>.<Zabbix用户手册> Zabbix服务端进程被分为不同的种类,每一种进程负责相应的任务,包括收集原始监控数据 ...

  4. 【基础知识】cache 管线(Pipeline)的建立便可以提升cpu的性能,为什么还要去发展多核的cpu?

    多管线 (Pipeline)的确可以提高主频,比如搭配 NetBurs架构的Pentium4,它拥有20级的管线技术,虽然可以轻易提高主频,但是效率会降低.而且随着频率的上升,功率也大幅上升温度问题也 ...

  5. Java -- List与数组转换

    list转数组 使用for循环 使用list.toArray(new String[]),不可以强制转换list.toArray(),因为数组在jvm是一个object表示的,是一个对象 数组转lis ...

  6. H5点击不同按钮跳转显示不同分页

    预期效果(页面1): 点击后显示对应的内容(页面2): HTML(页面1): 添加 onclick 跟 data-index     <!-- 3我的订单 -->     <div ...

  7. 浏览器无插件播放rtsp流解决方案

    1. 安装 FFmpeg 参考 CentOS下安装FFmpeg,特别详细. 我遇到的错误和解决办法: 缺少lame ffmpeg+libmp3lame库源码安装教程(CentOS) make ffmp ...

  8. C# Winform中FpSpread表格控件设置固定的(冻结的)行或列

    在项目中我们经常会用到固定表头的操作,FpSpread提供了冻结行或列的属性. 你可以冻结表单中的行或列(使其不可滚动). 你可以冻结任意个表单顶部的行,使其成为前导行,你也可以冻结左侧任意多个列,使 ...

  9. 01-Servlet 回顾

    通过url访问资源有三个步骤: 接收请求 处理请求 响应请求 web服务器:将某个主机上的资源映射为一个URL供外界访问,完成接收和响应请求 servlet容器:存放着servlet对象(由程序员编程 ...

  10. Win10系统设置开机自启动

    有时候,我们想设置某些软件开机时自动启动,操作步骤如下: 1. win+R 同时按住键盘上的win和R键打开运行窗口 2. shell:startup 输入shell:startup后回车 3. 添加 ...