动画演示平衡二叉树旋转

本文介绍了自平衡二叉查找树AVL树的概念,包括其平衡因子、旋转类型和插入操作。AVL树通过旋转操作保持平衡,保证查找效率。文章详细解释了LL、RR、LR和RL四种旋转类型,并提供了Flash动画演示。插入节点后,通过回溯修改平衡因子判断是否需要进行旋转,以保持树的平衡。此外,文章提到了删除节点的操作与插入类似,但也存在一些区别,如回溯方式和旋转方式的不同。
摘要由CSDN通过智能技术生成

转自:http://2002qiqi.blog.163.com/blog/static/17489036200912111929241/

 

我们知道在二叉查找树中,如果插入元素的顺序接近有序,那么二叉查找树将退化为链表,从而导致二叉查找树的查找效率大为降低。如何使得二叉查找树无论在什么样情况下都能使它的形态最大限度地接近满二叉树以保证它的查找效率呢?

前苏联科学家G.M. Adelson-Velskii 和 E.M. Landis给出了答案。他们在1962年发表的一篇名为 《An algorithm for the organization of information》的文章中提出了一种自平衡二叉查找树(self-balancing binary search tree)。这种二叉查找树在插入和删除操作中,可以通过一系列的旋转操作来保持平衡,从而保证了二叉查找树的查找效率。最终这种二叉查找树以他们的名字命名为“AVL-Tree”,它也被称为平衡二叉树(Balanced Binary Tree)。这里所说的平衡使我们想到了中庸之道,但有句话说得好,“中不偏,庸不易”。学会这种平衡术是一个相当痛苦的过程。

什么是平衡

为了保证平衡,AVL树中的每个结点都有一个平衡因子(balance factor,以下用BF表示),它表示这个结点的左、右子树的高度差,也就是左子树的高度减去右子树的高度的结果值。AVL树上所有结点的BF值只能是-1、0、1。反之,只要二叉树上一个结点的BF的绝对值大于1,则该二叉树就不是平衡二叉树。图1演示了平衡二叉树和非平衡二叉树。

AVL树的构造

如何构造一棵平衡二叉树呢?动态地调整二叉查找树平衡的方法为:每插入一个结点后,首先检查是否破坏了树的平衡性,如果因插入结点而破坏了二叉查找树的平衡,则找出离插入点最近的不平衡结点,然后将该不平衡结点为根的子树进行旋转操作,我们称该不平衡结点为旋转根,以该旋转根为根的子树称为最小不平衡子树。失衡状态可归纳为4种,它们对应着4种旋转类型。下面使用了Flash动画演示了这四种旋转类型,请确保你的电脑安装了Flash8.0以上版本的播放器,并且浏览器允许使用Flash。做这几个动画纯属好玩,希望有一天可以使用Silverlight做这些的动画。不过好象现在还没什么博客支持。

l         LL型旋转

  

如以上动画所示,插入结点5后,结点50的BF值由1变为2,此时结点50为旋转根。这种插入结点50的左孩子的左子树而导致失衡的情况需要进行LL旋转(LL意为左左)。可以观察到,虽然结点50的BF值由1变为了0,但最小不平衡子树在插入结点5前和旋转后的高度不变。

l         RR型旋转

 

 

如以上动画所示,插入结点90后,结点25的BF值由-1变为-2,此时结点25为旋转根。这种插入结点25的右孩子的右子树而导致失衡的情况需要进行RR旋转。最小不平衡子树在插入结点90前和旋转后的高度不变。

l         LR型旋转

 

 

插入旋转根的左孩子的右子树而导致失衡的情况需要进行LR旋转。这里演示了LR(L)和LR(R) 两种情况。插入结点前和旋转后的最小不平衡子树高度不变。

l         RL型旋转

 

  

插入旋转根的右孩子的左子树而导致失衡的情况需要进行RL旋转。这里演示了RL(L)和RL(R) 两种情况。插入结点前和旋转后的最小不平衡子树高度不变。

以上动画只演示了几种旋转类型的较复杂的情况,并没有全部演示,比如旋转根的左子树或右子树为空的情况,具体算法请参见稍后的代码。

AVL树上结点的插入

AVL算法的思想理解起来还是不太困难的,但如果真要使用代码实现就没那么简单了,它拥有超高的算法实现复杂度。我查了很多资料,大部分只给出主要算法代码,对于如何回溯修改BF值,如何处理不需要旋转的情况绝口不提,甚至对删除算法直接忽略。上网找资料,中文的,英文的全找了,大部分写代码不加注释,狂汗....,实在看不下去。大部分代码使用递归算法,C#实现更是少得可怜,在国外网站找到一个,但使用了三叉链表实现,多加了一个parent指针,总之无法找到让人满意的代码。最后一咬牙一跺脚,自己实现。最让人头痛的莫过于如何处理插入和删除后的回溯和修改BF值,庆幸的是最终还是按照我最初的想法比较漂亮地实现了AVL树。优点是:无递归;无parent指针;插入和删除操作使用同一旋转方法,使代码更为简化。缺点是:为了兼顾效率,有些地方的处理比较特殊,代码很难完全读懂。

下面对本算法做原理上的介绍:

1、 如何回溯修改祖先结点的平衡因子

我们知道,在AVL树上插入一个新结点后,有可能导致其他结点BF值的改变,哪些结点的BF值会被改变?如何计算新的BF值呢?要解决这些问题,我们必须理解以下几个要点:

l         只有根结点到插入结(橙色结点)点路径(称为插入路径)上的结点的BF值会被改变。如图2所示,只有插入路径上结点(灰色结点)的BF值被改变,其他非插入路径上结点的BF值不变。

 

l         当一个结点插入到某个结点的左子树时,该结点的BF值加1(如图2的结点50、43);当一个结点插入到某个结点的右子树时,该结点的BF值减1(如图2的结点25、30)。如何在程序中判断一个结点是插入到左子树还是右子树呢?很简单,根据二叉查找树的特性可以得出结论:如果插入结点小于某个结点,则必定是插入到这个结点的左子树中;如果如果插入结点大于某个结点,则必定插入到这个结点的右子树中。

l         修改BF值的操作需从插入点开始向上回溯至根结点依次进行,当路径上某个结点BF值修改后变为0,则修改停止。如图3所示,插入结点30后,首先由于30<43,将结点43的BF值加1,使得结点43的BF值由0变为 1;接下来由于30>25,结点25的BF值由1改为0;此时结点25的BF值为0,停止回溯,不需要再修改插入路径上结点50的平衡因子。道理很简单:当结点的BF值由1或-1变为0,表明高度小的子树添加了新结点,树的高度没有增加,所以不必修改祖先结点的平衡因子;当结点的BF值由0变为1或-1时,表明原本等高左右子树由于一边变高而导致失衡,整棵子树的高度变高,所以必须向上修改祖先结点的BF值。

<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值