平衡二叉树的判断,旋转,删除
作者:互联网
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