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. 使用javax.script包实现Java设置JS脚本中的变量

    下面例子中,我们通过javax.script包ScriptEngine.put()方法设置JS脚本中的变量,JS把所有在线用户输出. package ajava.code.javase; import ...

  2. 如何实现border-width:0.5px;

    工作中遇到了一个产品需求,要求把列表分割线改成0.5px,直接写成border:0.5px solid #cccccc;是不符合规范的写法,会存在Android和IOS手机上的兼容问题,故,我们可以利 ...

  3. 2017年php面试题汇总

    1.http状态码 200 这个没有什么好说的,是代表请求被正常的处理成功了 302 代表临时重定向 400 400表示请求报文中存在语法错误.需要修改后再次发送 403 表明请求访问的资源被拒绝了. ...

  4. Tomcat多域名访问

    对于域名解析相信很多小伙伴都了解过,就是我们在万网购买一个域名,比如hpugs.com,然后呢?我们希望域名与我们的服务器绑定,然后通过域名直接访问我们的项目,这就是本篇要和大家一起探讨的问题.下面开 ...

  5. Windows server2012如何运行Javaweb项目?

    最近用java写了个小项目,想要部署到服务器,于是买了个Windows server2012,但是不知道怎么部署,后来才知道需要配置java运行环境.经过一番研究最终搞定了.下边是我的个人总结,由于是 ...

  6. ViewPager +无限轮播+滑动速度修改+指示小点

    养成习惯,做过代码记录总结. ViewPager 使用记录 1. ViewPage 位于V4包. 2.主要用来做banner轮播. 3.原理:适配器重用提高效率,与listview等一个原理. 下面记 ...

  7. EntityFramework6与EntityFrameworkCore的区别

    EntityFramework6 EF6 是一个久经考验的数据库访问技术,发展多年,拥有许多特性,并且成熟稳定.2008年EF作为 .Net 3.5 Sp1 和Visual Studio 2008 S ...

  8. Kafka设计解析(八)- Exactly Once语义与事务机制原理

    原创文章,首发自作者个人博客,转载请务必将下面这段话置于文章开头处. 本文转发自技术世界,原文链接 http://www.jasongj.com/kafka/transaction/ 写在前面的话 本 ...

  9. Function Programming - 纯函数(Pure Function)

    纯函数的定义,非常重要!! Pure function 意指相同的输入,永远会得到相同的输出,而且没有任何显著的副作用. 老样子,我们还是从最简单的栗子开始: var minimum = 21; va ...

  10. [flask 优化] 由flask-bootstrap,flask-moment引起的访问速度慢的原因及解决办法

    一周时间快速阅读了400页的<javascript基础教程>,理解了主要概念.虽然对jquery.ajax.json这些方法的运用还不熟练,但在理清了概念之后解决了一个很久之前的疑问. 我 ...