AVL树是有平衡条件的二叉搜索树。这个平衡条件必须容易保持,而且需要保证树的深度是O(logN)。

  • AVL=BBST

  作为二叉搜索树的最后一部分,我们来介绍最为经典的一种平衡二叉搜索树:AVL树。回顾此前的几节,我们首先介绍的是二叉查找树BST。然而我们也能感受到,尽管从同时兼顾高效的静态操作

  和动态操作的角度讲,BST相对此前简单的向量和链表已经具有某种优势和潜质,但是毕竟它并不能保证这一点。其原因在于 它的高度,无论是从平均情况 还是最坏情况都不能保证做到足够的低,具体来说也就是做到logN以下当然——在BST中的确存在一种特殊的类型:也就是所谓的Complete Binary Tree它的高度可以达到严格的最小——也就是logN。然而相对于整体的BST这类BST的数量极少。而且将任何一棵树转化为一棵完全二叉树所需要的成本也太高,也正因如此,我们的建议是:或许应该适当地放松所谓“平衡”的标准。也就是说,只需考察某一类在渐近意义下不超O(logN)高度的树即可。而这样一类树,也就是我们所说的平衡二叉搜索树Balanced Binary Search Tree,BBST。

本节涉及概念及其关系

  比如我们这一节将要介绍的AVL树就是在这种意义下的一种BBST。以AVL树为代表的这些BBST

  首先并没有放弃渐近意义logN的复杂度底线。同时正因为它已经适度地放松了平衡的标准,所以通过精巧地设计,它们都可以具有这样一种属性:具体来说,对于任何一棵这样意义下的BBST在其生命期内即便在某次操作之后它不再满足BBST的条件, 游离到BBST这个范畴之外,我们也可以通过上节所介绍的等价变换迅速地将其重新转化为一棵等价的BBST。也就是说可以通过极小的代价就使之重新归入BBST的范畴。而这种极小的代价是多少呢?不出你的意料——依然是不超过logN。

  令刚刚失衡的搜索树重新恢复为一棵BBST的过程也称作重平衡Rebalance。而对于包括AVL树在内的各种BBST而言,其核心的技巧无非两条:

  • 如何来界定一种“适度的平衡”标准
  • 其次则是一整套重平衡的技巧和算法

  以下我们就以AVL树为例,具体地讲解如何完成这两项任务。

  先不管具体AVL树的要求,先来想想,如果我们自己来设计平衡标准,该如何考虑呢?最简单的想法是,要求左右子树具有相同的高度,那这种想法不要求树的高度尽量低。但是……极端情况下可能出现两条左右分叉的单链,这就很心碎了。所以这个标准是远远不够的。

  再想想有没有更好的办法,(可达鸭眉头一皱,发现事情并不简单hhhh)于是我们想到了另一种平衡条件——要求每个节点都必须有同高的左右子树。可是这样一来又会出问题:因为空树-1,那就只有具有2^k-1个节点的理想平衡树(Perfect Binary Tree)满足了,这个适用性就太狭窄了……很扎心。因此,虽然这个条件保证了树的高度很低,但是太苛刻了,我们还要再放宽点条件。

  后来,凶暴死宅的计算机科学家们(误)想到了一个绝妙的点子,而且我这里地方够大,写得下hhhhh。 用这个条件来限制:“让每个节点的左右子树高度最多差1”。可以证明,大致来讲一个AVL树的高度<=1.44log(N+2)-1.328。

  这棵树的左子树是高度为7且节点数最少的AVL树,右子树是高度为8且节点数最少的AVL树。可以看出在高度为h的AVL树中,最少节点数S(h)=S(h-1) + S(h-2) + 1。对于h=0,S(h) = 1;h=1,S(h)=2。函数S(h)与斐波那契数密切相关,由此可以推出上面的关于AVL树的高度上界。

  有了上面的感性认识后,我们来详细讨论、解释AVL树的各处细节,将上面给出的若干浓缩表述一一诠释。

  首先,给出在AVL的意义下,什么叫做适度的平衡。这要引入一个概念——平衡因子,凭它来判断一棵树是否是在AVL意义下的适度平衡

平衡因子(Balanced  Factor)就是左子树的高度与右子树高度之差,BalFac(v)=height(lc(v))- height(rc(v))。结合上面发明者的定义

  

  那么很显然,这是一颗AVL树(通过校验每个节点的balFac,每处都上上下下不超过1):

  

  AVL树只考虑左右子树的高度,所以只有所有节点满足全局的单调性即可,并不需要关心具体的数值。我们应该把更多的关注点集中于每个节点的平衡因子上。从这个例子可以看出,AVL树未必是CBT,反过来说,如此定义的AVL树,是否适度平衡呢?

  • AVL=适度平衡

  可以证明,AVL树的确是适度平衡的——也就是说 一棵规模为N的AVL树高度在渐近意义下是不超过logN的。

  

  实际上,为了证明规模固定的AVL树高度不会超过某个上限,我们可以等价地证明:在高度固定的情况下,一棵AVL树的节点也不至于太少。具体来说,可以证明这样一个事实:对于高度固定为h的AVL树其中所包含的节点数,至少是与h呈fibonacci数关系。

  

  为了得到这个关系式,我们需要借助递推式。具体而言可以证明这样一个递推式:S(h)=S(h-1) + S(h-2) + 1,这也就是上面所给出的那个递推式。如果我们将高度为h的AVL树的规模下限定义为S(h)的话,那么S(h)与S(h-1)以及S(h-2)之间就满足这么样一个叠加的关系。

  为此,我们来考察那棵高度为h同时规模达到最小的AVL树。

  

  既然它的规模要达到最少,所以它的左子树和右子树的规模也应该尽可能少,那么在AVL树的定义下,可变化的余地充其量不过其中一棵子树比另一棵子树高一层。不失一般性,假设左子树比右子树高出一层,因为它的高度为h-1,所以它的规模下限自然也就是S(h-1)。同理,作为高度为h-2的右子树,它的规模下限自然也就是S(h-2)。当然——还不要忘了这里的树根节点。这也就是为什么我们还要再附加上一个单位1。

  这个递推式是我们所有分析的核心,而以下只不过是一些简单的数学技巧而已。为此,我们不妨对它做一个等价变换——在左右各加一个1

 S(h)+1=[S(h-1)+1 ]+ [S(h-2) + 1]

  接下来,如果我们将S(h)+1定义为一个新的函数T(h),就会发现递推式的右侧变成T(h-1) +T(h-2)。这种形式是fibonacci数所特有的递推形式。所以我们可以断定它应该是等于fibonacci的某一项。那么具体的是从 h前后位移多少项呢?

  我们只需考察对应的边界情况即可:首先考察规模为1高度为0的AVL树。此时的T(h)应该等于1+1,这是fibonacci数的第三项。再来考察高度为1的AVL树,其规模最小也不至低于2,也就是左子树为一个节点、右子树为空的一棵AVL树,此时的T(h)应该是2+1,这是fibonacci数的第四项。

  由此可见 这里的T(h),只不过是fibonacci数向前位移了三位。我们知道fibonacci数,大致是呈Φ的指数形式增长,由此我们也得到了n关于高度h的一个下界。因此反过来等价地 n的对数,也就构成了h的一个上界。而这一点正是BBST所谓适度平衡的要求——这就意味着我们的AVL树的确是适度平衡的。

  好了,至此我们也就完成了第一项使命——也就是给出AVL意义下的,适度平衡标准。下一节将给出具体的重平衡(旋转操作)细节和插入新节点的算法。

AVL树 & 重平衡概念的更多相关文章

  1. AVL树(平衡二叉查找树)

    首先要说AVL树,我们就必须先说二叉查找树,先介绍二叉查找树的一些特性,然后我们再来说平衡树的一些特性,结合这些特性,然后来介绍AVL树. 一.二叉查找树 1.二叉树查找树的相关特征定义 二叉树查找树 ...

  2. 判断AVL树是否平衡

    AVL树是高度的平衡二插搜索树,其左子树和右子树的高度之差不超过1(树中的左子树和右子树都是AVL树),维持这个高度之差就要控制它的平衡因子.那么判断一颗AVL树是否平衡就需要判断它的左子树和右子树高 ...

  3. AVL树的平衡算法(JAVA实现)

      1.概念: AVL树本质上还是一个二叉搜索树,不过比二叉搜索树多了一个平衡条件:每个节点的左右子树的高度差不大于1. 二叉树的应用是为了弥补链表的查询效率问题,但是极端情况下,二叉搜索树会无限接近 ...

  4. 二叉树之AVL树的平衡实现(递归与非递归)

    这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八 ...

  5. AVL树 高度平衡的二叉查找树

    1.What is AVL tree? AVL tree 是一种特殊的二叉查找树,,首先我们要在树中引入平衡因子balance,表示结点右子树的高度减去左子树的高度差(右-左),对于一棵AVL树要么它 ...

  6. 自己动手实现java数据结构(七) AVL树

    1.AVL树介绍 前面我们已经介绍了二叉搜索树.普通的二叉搜索树在插入.删除数据时可能使得全树的数据分布不平衡,退化,导致二叉搜索树最关键的查询效率急剧降低.这也引出了平衡二叉搜索树的概念,平衡二叉搜 ...

  7. 高度平衡的二叉搜索树(AVL树)

    AVL树的基本概念 AVL树是一种高度平衡的(height balanced)二叉搜索树:对每一个结点x,x的左子树与右子树的高度差(平衡因子)至多为1. 有人也许要问:为什么要有AVL树呢?它有什么 ...

  8. AVL重平衡细节——插入

    话说这个系列鸽了好久,之前在准备语言考试,就没管博客了,现在暑假咱们继续上路! 每当我们进行一次插入之后,整棵AVL树的平衡性就有可能发生改变,为了控制整棵树的高度,我们需要通过一系列变换(重平衡)来 ...

  9. 006-数据结构-树形结构-二叉树、二叉查找树、平衡二叉查找树-AVL树

    一.概述 树其实就是不包含回路的连通无向图.树其实是范畴更广的图的特例. 树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合. 1.1.树的特性: 每个结点有零个或多个子 ...

随机推荐

  1. 实现一个websocket服务器-理论篇

    本文是Writing WebSocket servers的中文文档,翻译自MDNWriting WebSocket servers.篇幅略长,个人能力有限难免有所错误,抛砖引玉共同进步. websoc ...

  2. 比较DataTable中新旧数据

    内容不写了,代码上都做了写注释. 1   /**//// <summary>  2        /// 比较两个数据表,并返回比较结果表  3        /// 比较条件:  4   ...

  3. 搭建ntp时间服务器 ntp - (Network Time Protocol)

    第1章 ntp 1.1 ntp简介        NTP(Network Time Protocol,网络时间协议)是用来使网络中的各个计算机时间同步的一种协议.它的用途是把计算机的时钟同步到世界协调 ...

  4. scala(一)Nothing、Null、Unit、None 、null 、Nil理解

    相对于java的类型系统,scala无疑要复杂的多!也正是这复杂多变的类型系统才让OOP和FP完美的融合在了一起! Nothing: 如果直接在scala-library中搜索Nothing的话是找不 ...

  5. 移动端h5拍照压缩即时上传后台并预览

    项目经理让迭代一个功能,实时预览并上传到后台的功能,听到这立马想起了几个第三方插件去实现,mui  和api cloude万万没想到的是这个app前面使用ios 和安卓原生写的,然后mui和api c ...

  6. [C#]使用TcpListener及TcpClient开发一个简单的Chat工具

    本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 本文使用的开发环境是VS2017及dotNet4.0,写此随笔的目的是给自己及新开发人员作为参 ...

  7. shopxx--权限功能测试

    shiro权限控制 一.添加角色 1.打开   系统→角色管理,点击 添加 赋予当前角色对应的权限 二.添加管理员(即用户管理) 添加用户,赋予刚才添加的角色 三.用新用户登录,进行测试 登录结果

  8. angular2.x指令

    1.指令 *ngIf: 判断 isActive 为true时 <user-detail> 生效展示 <user-detail *ngIf="isActive"&g ...

  9. 书籍推荐系列之一 -- 《凤凰项目:一个IT运维的传奇故事》

    博客已经完全更新了名字,新的名字,新的开始,想让自走向新的道路是很难的,走出舒适圈说了好久,也是时候开始行动了,今天就从写博客开始. 今天给大家推荐一本书,<凤凰项目:一个IT运维的传奇故事&g ...

  10. JAVA 中LinkedHashMap要点记录

    JAVA 中LinkedHashMap要点记录 构造函数中可能出现的几个参数说明如下: 1.initialCapacity 初始容量大小,使用无参构造方法时,此值默认是16 2.loadFactor ...