其他分享
首页 > 其他分享> > 平衡二叉树的判断,旋转,删除

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

作者:互联网

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;//返回根结点
}

 

 

 

标签:right,Val,删除,AVLNode,height,二叉树,旋转,节点
来源: https://blog.csdn.net/qq_39230153/article/details/121014338