AVL树(平衡二叉树)

一颗AVL树是其每个节点的左子树和右子树的高度最多差1二叉查找树(空树的高度定位-1)。
二叉查找树的性质:对于树中的每个节点X,它的左子树中所有项的值小于X中的项,而它的右子树的所有项的值大于X中的项。

这里写图片描述

1.AVL树的插入

在树中插入一个值可能破坏AVL树的性质,所以我们要对树进行调整,这一操作就是旋转
在插入以后,只有从插入点到根节点的的路径上的节点的平衡可能改变,因为只有这些节点的子树可能发生变化。假设a为必须重新平衡的节点,那么不平衡的情况是下面四种:

  • 对a的左儿子的左子树进行一次插入
  • 对a的左儿子的右子树进行一次插入
  • 对a的右儿子的左子树进行一次插入
  • 对a的右儿子的右子树进行一次插入

对于插入发生在外面的情况(即左-左和右-右),通过对树进行单旋转完成调整,而对于初入发生在内部的情况(即左-右和右-左),通过对树进行双旋转来完成调整

2.单旋转

这里写图片描述

节点k2不满足AVL的性质,其左子树比右子树深2层。为了使其平衡,我们要将X提上一层。调整的方法可以这样形容:将树想象成是柔软灵活的,抓住子节点k1,闭上你的双眼,使劲摇动它,在重力的作用下,k1变成了新的根。再者根据二叉查找树的性质,原来的树中k2>k1,于是在新树中k2变成k1的右儿子。子树Y包含原树中介于k1和k2之间的那些节点,那么它就放在了k2的左儿子的位置上。

这里写图片描述

3.双旋转

这里写图片描述
这里写图片描述
对于图示左边,用单旋转调整,对k1,k2之间进行旋转发现解决不了问题,我们只能将k2作为新的根。这使得k1成为k2的左子树,k3成为k2的右子树。

4.插入的基本思路

为将项是X的一个新节点 插入到一棵AVL树T中去,我们递归地结果X插入到T的相应的子树(称为Tlr)中,如果Tlr的高度不变,则插入完成,否则T中出现了高度不平衡,则根据情况进行单旋转或者双旋转的调整,更新高度(并且解决好与树的其余部分的链接)从而完成插入。

5.代码部分

  • AVL树的申明
public class AVLnode {
    AVLnode(int element)
    {
        this(element,null,null);
    }
    AVLnode(int element, AVLnode lt, AVLnode rt)
    {
        this.element = element;
        left = lt;
        right = rt;
    }
    int element;
    AVLnode left;
    AVLnode right;
    int height;
}
  • 单旋转(左-左)(对于右-右的情况是对称的)

    这里写图片描述

     private AVLnode rotateWithLeftChild(AVLnode k2)
     {
         AVLnode k1 = k2.left;
         k2.left = k1.right;
         k1.right  = k2;
         k2.height = Math.max(height(k2.left),height(k2.right))+1;
         k1.height = Math.max(height(k1.left),height(k1.right))+1;
         return k1;
     }
  • 双旋转(左-右)(右-左的情况是对称的)
    这里写图片描述
     private AVLnode doubleWithLeftChild(AVLnode k3)
     {
         k3.left = rotateWithRightChild(k3.left);
         return rotateWithLeftChild(k3);
     }
  • 插入(总代码)
package AVL;

public class test {
     //得到高度
     private int height(AVLnode t)
     {
         return t==null?-1:t.height;
     }
     //插入
     private AVLnode insert(int x, AVLnode t)
     {
         if( t== null)
             return new AVLnode(x,null,null);

         if(x<t.element)
         {
             t.left = insert(x,t.left);
             if(height(t.left)-height(t.right)==2)
                 if(x<t.left.element)
                     t = rotateWithLeftChild(t);
                 else
                     t = doubleWithLeftChild(t); 
         }
         else if(x>t.element)
         {
             t.right = insert(x,t.right);
             if(height(t.right)-height(t.left)==2)
                 if(x>t.right.element)
                     t = rotateWithRightChild(t);
                 else
                     t = doubleWithRightChild(t); 
         }
         t.height = Math.max(height(t.left),height(t.right))+1;
         return t;
     }
     //左-左
     private AVLnode rotateWithLeftChild(AVLnode k2)
     {
         AVLnode k1 = k2.left;
         k2.left = k1.right;
         k1.right  = k2;
         k2.height = Math.max(height(k2.left),height(k2.right))+1;
         k1.height = Math.max(height(k1.left),height(k1.right))+1;
         return k1;
     }
     //右右
     private AVLnode rotateWithRightChild(AVLnode k2)
     {
         AVLnode k1 = k2.right;
         k2.right = k1.left;
         k1.left  = k2;
         k2.height = Math.max(height(k2.left),height(k2.right))+1;
         k1.height = Math.max(height(k1.left),height(k1.right))+1;
         return k1;
     }
     //左-右
     private AVLnode doubleWithLeftChild(AVLnode k3)
     {
         k3.left = rotateWithRightChild(k3.left);
         return rotateWithLeftChild(k3);
     }
     //右-左
     private AVLnode doubleWithRightChild(AVLnode k3)
     {
         k3.right = rotateWithLeftChild(k3.right);
         return rotateWithRightChild(k3);
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值