平衡二叉树的判断,旋转,删除

1.平衡二叉树(AVL)的判断

平衡二叉树要怎么判断,在判断之前我们需要了解一个重要概念-------树的高度和深度。

树的高度,顾名思义,从下往上看;树的深度,顾名思义,从一棵树的上面往下看,这里要注意,根节点的深度和叶子节点的高度是从0开始。

介绍了高度,引入如下满足条件:

条件一:它必须是二叉查找树;(看之前文章有)

(二叉查找树就是要满足左节点的值< 根节点的值< 右节点的值)

条件二:每个节点的左子树和右子树的高度差至多为1;

 

以上这颗树就不是平衡二叉树,右边叶子节点“43”的值小于“45”。这个很好判断

 

 

同样这棵树也不满足平衡二叉树的要求,看节点“45” ,左边节点45的左子树下有两个,“44”和“43”,数出“45”的高度为2,右节点没有,高度为0。高度差为2,不满足条件二。

那么真正的平衡二叉树是什么样的呢?

重点来了,遇到不平衡的二叉树要怎么调整呢?往下看

 2.二叉树的调整

一般会遇到四种情况,分别是LL型,RR型,LR型,RL

LL型(顺时针调整)

 

很明显不是平衡二叉树,因为A1.val >A2.Val >A3.Val(各个节点的值),所以要把最大的二叉树节点放到右边,最小的在左边,如下图所示:

private AVLNode<T> singleRotateLeft(AVLNode<T> x){
    //把w结点旋转为根结点
    AVLNode<T> w=  x.left;
    //同时w的右子树变为x的左子树
    x.left=w.right;
    //x变为w的右子树
    w.right=x;
    //重新计算x/w的高度
    x.height=Math.max(height(x.left),height(x.right))+1;
    w.height=Math.max(height(w.left),x.height)+1;
    return w;//返回新的根结点
}

 RR型(逆时针调整)

右边的往左动,A3.Val > A2.Val > A1.Val.于是A3最右边,A1最左边

private AVLNode<T> singleRotateRight(AVLNode<T> w){

    AVLNode<T> x=w.right;

    w.right=x.left;
    x.left=w;

    //重新计算x/w的高度
    w.height=Math.max(height(w.left),height(w.right))+1;
    x.height=Math.max(height(x.left),w.height)+1;

    //返回新的根结点
    return x;
}

 

 LR型

 

A1.Val >A3.Val >A2.Val,故调整后变成下图:

 左右旋转代码如下:

/**
* 左右旋转(LR旋转) x(根) w y 结点 把y变成根结点
*/
private AVLNode<T> doubleRotateWithLeft(AVLNode<T> x){
    //w先进行RR旋转
    x.left=singleRotateRight(x.left);
    //再进行x的LL旋转
    return singleRotateLeft(x);
}

 RL型

A2.Val > A3.Val > A1.Val ,所以A3变成根节点,A2变成右边节点。旋转完成后如下图所示:

 代码参考:

/**
* 右左旋转(RL旋转)
*/
private AVLNode<T> doubleRotateWithRight(AVLNode<T> x){
    //先进行LL旋转
    x.right=singleRotateLeft(x.right);
    //再进行RR旋转
    return singleRotateRight(x);
}

基本方法介绍完了,接下来用一组数据为 2,1,0,3,4,5,6,9,8,7的10个节点来构造平衡二叉树,试一试吧

首先,“2”变成根节点,接着是“1”和“0”,变成LL型,然后旋转:

 

 紧接着是“3”,应该成为“2”的右子树,此时是平衡的,再插入“4”,变成“3”的右子树,2-3-4为RR型:

 

 

“4”的右边插入“5”, 1-3-4为RR型,旋转为:

“6”放到“5”的右边,4-5-6为RR型,旋转:

 接着插入“9”和“8”,6-9-8为RL型,旋转:

 

 

还剩一个“7” ,3-5-8为RR型,5-8-9为RR型,8-9-7为RL型,旋转:

 

 

get!

 


/**
*插入代码
*/
@Override
public void insert(T data) {
   if (data==null){
       throw new RuntimeException("data can\'t not be null ");
   }
   this.root=insert(data,root);
}

private AVLNode<T> insert(T data , AVLNode<T> p){

   //说明已没有孩子结点,可以创建新结点插入了.
   if(p==null){
       p=new AVLNode<T>(data);
   }else if(data.compareTo(p.data)<0){//向左子树寻找插入位置
       p.left=insert(data,p.left);

       //插入后计算子树的高度,等于2则需要重新恢复平衡,由于是左边插入,左子树的高度肯定大于等于右子树的高度
       if(height(p.left)-height(p.right)==2){
           //判断data是插入点的左孩子还是右孩子
           if(data.compareTo(p.left.data)<0){
               //进行LL旋转
               p=singleRotateLeft(p);
           }else {
               //进行左右旋转
               p=doubleRotateWithLeft(p);
           }
       }
   }else if (data.compareTo(p.data)>0){//向右子树寻找插入位置
       p.right=insert(data,p.right);

       if(height(p.right)-height(p.left)==2){
           if (data.compareTo(p.right.data)<0){
               //进行右左旋转
               p=doubleRotateWithRight(p);
           }else {
               p=singleRotateRight(p);
           }
       }
   }
   else
    ;//if exist do nothing
   //重新计算各个结点的高度
   p.height = Math.max( height( p.left ), height( p.right ) ) + 1;

   return p;//返回根结点
}

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值