平衡二叉查找树的概念就不多介绍了,这边主要说明一下如何进行插入操作
在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是: 旋转 。 下面我们归纳一下平衡旋转的4种情况
1) 绕某元素左旋转 LL(右子树出现右不平衡)
分析一下:在插入数据100之前,左图中的 ST树只有80节点的平衡因子是-1(左高-右高),但整棵树还是平衡的。加入100之后,80节点的平衡因子就成为了-2,此时平衡被破坏。需要左旋转成右图。
当树中节点X的右孩子的右孩子上插入新元素,且平衡因子从-1变成-2后,就需要绕节点X进行左旋转。
2) 绕某元素右旋转 RR(左子树出现左不平衡)
当树中节点X的左孩子的左孩子上插入新元素,且平衡因子从1变成2后,就需要绕节点X进行右旋转。
3) 绕某元素的左子节点左旋转,接着再绕该元素自己右旋转。 此情况下就是左旋与右旋 的结合,具体操作时可以分解成这两种操作,只是围绕点不一样而已。LR(左子树出现右不平衡)
当树中节点X的左孩子的右孩子上插入新元素,且平衡因子从1变成2后,就需要先绕X的左子节点Y左旋转,接着再绕X右旋转
4) 绕某元素的右子节点右旋转,接着再绕该元素自己左旋转。 此情况下就是 右旋与左旋 的结合,具体操作时可以分解 成这两种操作,只是围绕点不一样而已 。RL(右子树左不平衡)
当树中节点X的右孩子的左孩子上插入新元素,且平衡因子从-1变成-2后,就需要 先绕X的右子节点Y右旋转,接着再绕X左旋转
附上这几种操作的java版本的代码,代码自己用不同的用例测过,如果有什么地方没有考虑到,欢迎指正^0^
import java.util.ArrayList;
import java.util.List;
public class AVL {
class TreeNode{
int value;
int bf;
TreeNode left,right;
TreeNode(int v){
value = v;
bf = 0;
}
}
public TreeNode buildTree(int[] nums){
if(nums.length == 0) return null;
TreeNode PRoot = new TreeNode(0);
TreeNode root = new TreeNode(nums[0]);
//为了能让后面可以改变root的地址而设
PRoot.left = root;
for(int i = 1; i < nums.length ; i++){
insertTree(nums[i],PRoot);
}
return root;
}
public void insertTree(int num,TreeNode PRroot){
if(PRroot.left == null)
return;
TreeNode A=PRroot.left , B=PRroot.left ;
TreeNode insertNode = new TreeNode(num);
TreeNode temp = PRroot.left ;
TreeNode AFather = null,tempFather = null;
while(temp != null){
//找到从下到上最近的可能出现不平衡的节点
if(temp.bf != 0){
A = temp;
AFather = tempFather;
}
tempFather = temp;
if(num < temp.value)
temp = temp.left;
else
temp = temp.right;
}
//插入孩子
if(num > tempFather.value)
tempFather.right = insertNode;
else
tempFather.left = insertNode;
adjustBalance(A,AFather,insertNode,PRroot);
// printTree(PRroot);
}
public TreeNode updateBF(TreeNode insert,TreeNode node){
if(insert.value < node.value){
node.bf +=1;
return node.left;
}
else {
node.bf -= 1;
return node.right;
}
}
public void adjustBalance(TreeNode A,TreeNode AFather,TreeNode insert,TreeNode PRoot){
//确定B节点,修改A的bf
TreeNode B = updateBF(insert,A);;
//B不是插入点则也需要更新B的bf
System.out.println("B.value= " + B.value);
//在原来都平衡的一边加上一个值,A就会是root,所以要修改从B到插入节点之间的bf值
TreeNode temp = B;
while(temp.value != insert.value){
updateBF(insert,temp);
if(insert.value < temp.value)
temp = temp.left;
else
temp = temp.right;
}
//LL
if(A.bf == 2 && B.bf == 1){
A.left = B.right;
B.right = A;
A.bf = 0;
B.bf = 0;
updateChild(AFather,A,B,PRoot);
}
//RR
else if(A.bf == -2 && B.bf == -1){
A.right = B.left;
B.left = A;
A.bf = 0;
B.bf = 0;
updateChild(AFather,A,B,PRoot);
}
//LR
else if(A.bf == 2 && B.bf == -1){
TreeNode C = B.right;
//先往左转成LL
B.right = C.left;
C.left = B;
//LL
A.left = C.right;
C.right = A;
//插入的点如果比C大最后会落在A的左边,比C小会落在B的右边
//A的右边 和B的左边一定有元素
if(insert.value > C.value){
A.bf = 0;
B.bf = -1;
C.bf = 0;
}
else if(insert.value < C.value) {
A.bf = 1;
B.bf = 0;
C.bf = 0;
}
//插入点就是C的话
else{
A.bf = 0;
B.bf = 0;
}
updateChild(AFather,A,C,PRoot);
}
//RL
else if(A.bf == -2 && B.bf == 1){
TreeNode C = B.left;
//先转成RR
B.left = C.right;
C.right = B;
//RR
A.right= C.left;
C.left = A;
//插入的点如果比C大最后会落在B的左边,比C小会落在A的右边
//因为B右边和A的左边一定会有元素
if(insert.value > C.value){
B.bf = 0;
A.bf = 1;
C.bf = 0;
}
else if(insert.value < C.value){
A.bf = 0;
B.bf = -1;
C.bf = 0;
}
//C就是要插入的元素
else{
A.bf = 0;
B.bf = 0;
}
updateChild(AFather,A,C,PRoot);
}
}
public void updateChild(TreeNode father,TreeNode originChild,TreeNode newChild,TreeNode PRoot){
if(father == null)
PRoot.left = newChild;
else if(originChild == father.left)
father.left = newChild;
else
father.right = newChild;
}
public void printTree(TreeNode tree){
if(tree.left == null) return;
List<TreeNode> nodes = new ArrayList<TreeNode>();
nodes.add(tree.left);
printNode(nodes,"value");
System.out.println("***************");
printNode(nodes,"bf");
System.out.println("#################");
}
public void printNode(List<TreeNode> nodes,String type){
if(nodes.size() == 0) return;
List<TreeNode> childs = new ArrayList<TreeNode>();
for(TreeNode node:nodes){
if(type.equals("value"))
System.out.print(node.value + " ");
else
System.out.print(node.bf + " ");
if(node.left != null)
childs.add(node.left);
if(node.right != null)
childs.add(node.right);
}
System.out.println();
printNode(childs,type);
}
public static void main(String[] args){
int[] nums={10,20,29,24,12,53,45,90,100,290,28};
AVL avl = new AVL();
TreeNode tree = avl.buildTree(nums);
avl.printTree(tree);
}
}