平衡二叉树AVL的实现(递归及非递归)

转载于https://www.cnblogs.com/leihui/p/6002418.html

这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现

下面这张图绘制了需要旋转操作的8种情况。(我要给做这张图的兄弟一个赞)后面会给出这八种情况对应平衡实现。

 

[1]


 

情况1-2:

  这种需要旋转的结构一般称之为为LL型,需要右旋(顺时针旋转)。

  我用一个图来抽象一下这两个情况,画的不好,我尽量表达吧。

  

  此时需要对一个进行平衡操作,方法为:

  1.     将甲的左子树换为乙的右子树。
  2.   乙的右子树换为A.
  •   非递归实现的代码为:

复制代码

 

复制代码

 

  非递归的操作在旋转前会充分考虑所有的旋转情况,目的是提早调整甲下面各节点的高度。

  之后再进行旋转操作,这一点与递归的不同,可见递归是平衡完后再进行的高度调整。

  •   递归实现代码为:

复制代码

 

复制代码

 

情况3-4:

  这种需要旋转的结构一般称之为RR型,需要左旋(逆时针旋转)。

  需要对一个进行平衡操作,方法为:

  1.   将甲的右子树换为乙的左子树;
  2.   乙的左子树换为甲

  

  •   非递归的实现为:

复制代码




复制代码

 

  •   递归实现为:

复制代码

 

复制代码

 

情况5-6: 

  这种需要旋转的结构一般称之为LR型,需要双旋转,即两次单旋。分别为左旋和右旋。

  需要对一个进行平衡操作,方法为:

  1.   对B(A->左)做左旋
  2.   对一个做右旋

  这个递归与非递归的方式都是一样的。

  •   非递归:
 

 

  •   递归:
 

 

  但是有没有一次性到位的方法呢?有的

  我把非递归的两个函数展开:

  发现最后一步都是确定与父节点的关系,并不是旋转中的具体过程,于是可以简化为这样:

复制代码






复制代码

 

 

情况7-8:

  这种需要旋转的结构一般称之为RL型,需要双旋转,即两次单旋。分别为右旋和左旋。

  需要对一个进行平衡操作,方法为:

  1.   对乙进行右旋
  2.   对一个进行左旋

  同样,递归与非递归版本是一样的。

  •   非递归:
 

 

  •   递归:
 

 

 

  同样,也有一次性到位的方法:

复制代码






复制代码

 

 


 

 

下面是实现部分:

 

0.结构声明 [2]

复制代码

 

复制代码

 

 

1.类中提供的API

复制代码





    









复制代码

 

 

2.获取高度:
  因为在MAX()函数获取结束后需要1,所以这里的目的是将叶节点的高度想办法为0。

 

 

 

3.插入操作:

  •   递归

  通过回溯的方式找到插入的位置,先平衡后调整高度;

  哈哈,有一个很有趣的细节为什么同时判断高度差一个是

  if(getHeight(_T-> left) - getHeight(_T-> right)== 2)

  而另一个是

  if(getHeight(_T-> right) - getHeight(_T-> left)== 2)

  因为这里已经知道了插入发生在哪边了,所以肯定是插入的那边会有破坏平衡的可能,不会造成尴尬的(小 - 大)的局面。

复制代码

    

复制代码

 

  

  •   非递归[3]:

  可以发现,非递归的实现是先调整高度再平衡,但是要提前考虑所有情况。

  考虑左子树的情况:

复制代码

        
        

复制代码

 

 

   考虑右子树的情况:

复制代码

 

复制代码

 

 

 总结:

  递归真是神奇啊,对子树的处理递归的很漂亮,代码量是一方面,代码逻辑的清晰性也是非递归程序鲜有的。

  用这个来学习递归算法真是好工具,希望对于我后面复习图论有帮助。

  这篇文章中所述的非递归程序我并没有实现,肯定有疏忽的地方,欢迎大家指正。

 

完整示例中还有一个showThisTree(),它可以打印出漂亮的平衡二叉树。

代码相关请见我的github上

 

[1]    AVL树的旋转操作图解最详细

[2]左等价leftChild,同理,右也等价rightChild。

[3]    平衡二叉树(AVL)的插入和删除详解(上)

[4]参考教材  数据结构与算法分析:C语言描述(原书第2版)[美] MarkAllenWeiss着

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值