一、平衡二叉树
定义特点是1.满足二叉查找树的特点
=》左子树小于根节点
=》右子树大于根节点
2.它的|左子树、与右子树的深度差|<2
=>目的是要充分的利用二叉查找树的特性,维护深度
二、实现
为了维护它的特性,在插入添加的过程中会变得很复杂。参考
1.首先来看下旋转
=》对于树中的元素,还按照这个规则来重新实现
例如:
2.那么在平衡二叉树的插入过程当中会遇到哪些情况?
(1)LL
解决办法=》找到最根的左、右子树深度不平衡的节点
=》然后根的左子树变根节点
=》然后根可以变成右子树
=》如果根的左子树有右子树,则变为此根的左子树
(2)RR
解决办法:同上相反
(3)LR
解决办法:首先调整成LL情况如何调整?
(4)RL
解决办法:首先调整成RR如何调整那?
三、代码实现
=》节点结构
=》查询
=》添加
=》实例化
=》中序遍历
=》效果图
=》删除节点(实现了在)
//节点结构
class TreeNode{
private int num;
private int diff; //平衡因子
private TreeNode leftChild;
private TreeNode rightChild;
//get /set method
}
//得到当前节点的深度
/*
* This will through recursion to get the deep
* but the deep does not contain the current node
* =>judge is null
* =>null return
* =>is not
* =>get the left and right
* =>judge the left right return the max
* */
public static int getDeep(TreeNode t){
if(t==null)return 0;
int leftDeep=0;
int rightDeep=0;
leftDeep+=getDeep(t.getLeftChild());
rightDeep+=getDeep(t.getRightChild());
return leftDeep>=rightDeep?leftDeep+1:rightDeep+1;
}
//实例化当前的节点的平衡因子
/*
* initialization the node attribute diff
* */
public static void initDiff(TreeNode t){
if(t==null)return;
int leftDeep=getDeep(t.getLeftChild());
int rightDeep=getDeep(t.getRightChild());
t.setDiff(leftDeep-rightDeep);
}
//递归实现插入操作
//解决了插入后平衡因子改变的记录
/*
*How to insert a number
*There have two method to input it
*
*if just insert the BST you can not user the recursion
*you can just get the insert node position
*
*use the recursion can get the path
*that after insert the balance is interrupted
* */
public static TreeNode insertBST(TreeNode t,int num){
//if(searchBST(num))return false;
if(t==null){
t=new TreeNode();
t.setNum(num);
t.setLeftChild(null);
t.setRightChild(null);
t.setDiff(0);
}else{
// if(t.getNum()==num){
// return null;
// }
//there have the recursion
//insert left
if(t.getNum()>num){
t.setLeftChild(insertBST(t.getLeftChild(), num));
initDiff(t);
//left-right=2;
if(t.getDiff()==2){
if(num<t.getLeftChild().getNum())
t=LL(t);
else
t=LR(t);
}
}else if(t.getNum()<num){
t.setRightChild(insertBST(t.getRightChild(),num));
initDiff(t);
if(t.getDiff()==-2){
if(num>t.getRightChild().getNum())
t=RR(t);
else
t=RL(t);
}
}
}
return t;
}
//四个旋转情况
//LL
/*
* c b |
* / /\ |
* b => a c |
* / |
* a |
* */
public static TreeNode LL(TreeNode t){
TreeNode tn=t.getLeftChild();
t.setLeftChild(tn.getRightChild());
tn.setRightChild(t);
initDiff(tn);
initDiff(t);
return tn;
}
//RR
/*
* c d |
* \ /\ |
* d => c e |
* \ |
* e |
*
* */
public static TreeNode RR(TreeNode t){
TreeNode tn=t.getRightChild();
t.setRightChild(tn.getLeftChild());
tn.setLeftChild(t);
initDiff(tn);
initDiff(t);
return tn;
}
//LR
/*
* d d
* / /
* a => b =>
* \ /
* b a
* */
public static TreeNode LR(TreeNode t){
t.setLeftChild(RR(t.getLeftChild()));
return LL(t);
}
//RL
public static TreeNode RL(TreeNode t){
t.setRightChild(LL(t.getRightChild()));
return RR(t);
}
//删除操作
//当时在查询树的时候处理思路是这样的
//获得删除的节点,如果是叶子节点,那么它的父节点直接指向null
//如果只有左子树,则左子树替代位置
//如果只有右子树,右子树替代位置
//如果都有则,要么从最左边找到最大的代替然后,删除它
//或者从最右边找到最小的代替然后删除
//此处的思路是这样的
//如果没有右子树那么 左子树代替了
//如果有右子树,那么找到最小的右子树值,替换,删除
public static TreeNode deleteAVL(TreeNode t,int num){
if(t==null)return null;
else{
if(t.getNum()==num){
//在查询二叉树的时候删除分为了
//叶子节点、只有左子树、只有右子树、有左右子树
//
if(t.getRightChild()==null)t=t.getLeftChild();
else{
TreeNode tn=t.getRightChild();
while(tn.getLeftChild()!=null)
tn=tn.getLeftChild();
t.setNum(tn.getNum());
t.setRightChild(deleteAVL(t.getRightChild(),t.getNum()));
initDiff(t);
t.setDiff(t.getDiff()+1);
}
return t;
}else if(t.getNum()>num){
t.setLeftChild(deleteAVL(t.getLeftChild(),num));
}else{
t.setRightChild(deleteAVL(t.getRightChild(),num));
}
}
initDiff(t);
//删除一个节点结果只有+1 -1
if(t.getDiff()==2){
//必定是+1所致
//删除的是右节点
//判断是LL 偶然LR
if(t.getLeftChild().getDiff()==1)
t=LL(t);
else if(t.getLeftChild().getDiff()==-1)
t=LR(t);
}else if(t.getDiff()==-2){
if(t.getRightChild().getDiff()==-1||t.getRightChild().getDiff()==0)
t=RR(t);
else if(t.getRightChild().getDiff()==1)
t=RL(t);
}
return t;
}