树结点:
public class myAVLTree {
public TreeNode root;
static class TreeNode {
public TreeNode left;
public TreeNode right;
public TreeNode parent;
public int val;
public int bf; //平衡因子(blance factor)
//bf = 右子树高度 - 左子树高度
public TreeNode(int val) {
this.val = val;
}
}
}
代码
//插入结点的原理和二叉搜索树一样
public boolean insert(int val){
TreeNode node = new TreeNode(val);
if(root == null){
root = node;
return true;
}
TreeNode cur = root;
TreeNode parent = null;
while(cur != null){
if(val > cur.val){
parent = cur;
cur = cur.right;
}else if(val < cur.val){
parent = cur;
cur = cur.left;
}else{
//相等
return false;
}
}
//插入到叶子结点
if(parent.val < val){
node = parent.right;
}else{
node = parent.left;
}
//平衡因子修改
node.parent = parent;
cur = node;
while(parent != null){
if(cur == parent.right){
//如果结点插在父结点右边,则右树高度增加,平衡因子++
parent.bf++;
}else{
//如果结点插在父结点左边,则左树高度增加,平衡因子--
parent.bf--;
}
//检查当前的平衡因子
if(parent.bf == 0){
break;
}else if(parent.bf == 1 || parent.bf == -1){
//继续向上检查平衡因子 可能存在不平衡的情况
node = parent;
parent = parent.parent;
}else{
if(parent.bf == 2){
if(cur.bf == 1){
//右树高度高了,需要降低右树高度,进行左旋操作
RotateL(parent);
}else{
//cur.bf == -1
RotateRL(parent);
}
}else{
//parent.bf == -2
//左树高度高了,需要降低左树高度
if(cur.bf == -1){
//右旋
RotateR(parent);
}else{
//cur.bf == 1
//左右双璇
RotateLR(parent);
}
}
break;
}
}
return true;
}
左单旋
两种情况
1.定义结点时TreeNode subR = parent.right TreeNode subRL = subR.left
当subRL != null时
2.subRL == null时
1.subRL != null
//左单旋
public void RotateL(TreeNode parent){
TreeNode subR = parent.right;
TreeNode subRL = subR.left;
//提前定义好父亲结点的父结点,因为后面父亲结点的指向就被改变了
TreeNode pParent = parent.parent;
subR.left = parent;
parent.right = subRL;
//与右旋一样的情况 subRL可能为null
if(subRL != null){
subRL.parent = parent;
}
parent.parent = subR;
//判断是否是根结点
if(parent == root){
root = subR;
root.parent = null;
}else{
if(pParent.left == parent){
pParent.left = subR;
}else{
parent.right = subR;
}
}
//改变平衡因子
parent.bf = 0;
subR.bf = 0;
}
2.subRL==null
//右旋
public void RotateR(TreeNode parent){
TreeNode subL = parent.left;
TreeNode subLR = subL.right;
//父结点的上面还存在着他的父节点
TreeNode pParent = parent.parent;
//进行右旋操作
subL.right = parent;
//注意这里还有一种情况:subLR为null
parent.left = subLR;
if(subLR != null){
subLR.parent = parent;
}
parent.parent = subL;
if(parent == root){
//判断是否为根节点
subL = root;
root.parent = null;
}else{
if(pParent.left == parent){
pParent.left = subL;
}else{
parent.right = subL;
}
}
//将现在的父结点指向原来父亲结点的父结点
subL.parent = pParent;
//修改平衡因子
subL.bf = 0;
parent.bf = 0;
}
右单璇
和左单旋一样,也是有两种情况
1.subLR != null
2.subLR == null
//右旋
public void RotateR(TreeNode parent){
TreeNode subL = parent.left;
TreeNode subLR = subL.right;
//父结点的上面还存在着他的父节点
TreeNode pParent = parent.parent;
//进行右旋操作
subL.right = parent;
//注意这里还有一种情况:subLR为null
parent.left = subLR;
if(subLR != null){
subLR.parent = parent;
}
parent.parent = subL;
if(parent == root){
//判断是否为根节点
subL = root;
root.parent = null;
}else{
if(pParent.left == parent){
pParent.left = subL;
}else{
parent.right = subL;
}
}
//新父结点指向原父结点的父结点
subL.parent = pParent;
//修改平衡因子
subL.bf = 0;
parent.bf = 0;
}
双旋
上面的单旋模式中,我们可以总结规律-----当前结点的平衡因子和父结点的平衡因子的符号总是相同的,而双旋模式就出现在当前结点的平衡因子和父亲结点的平衡因子相反的情况且父亲的平衡因子=-2or2,这种情况下无论你左旋还是右旋,只旋转一次的话是得不到高度平衡的,故需要旋转两次
左右双旋
当subLR.bf=1时
2.subLR.bf=-1时
//左右双璇
public void RotateLR(TreeNode parent){
TreeNode subL = parent.left;
TreeNode subLR = subL.right;
int bf = subLR.bf;
//先左旋
RotateL(parent.left);
//再右旋
RotateR(parent);
//subLR的平衡因子影响着结点的平衡因子
if(bf == -1){
subL.bf = 0;
subLR.bf = 0;
parent.bf = 1;
}else if(bf == 1){
subL.bf = -1;
subLR.bf = 0;
parent.bf = 0;
}
}
右左双旋
subRL.bf=1时
subRL=-1时
public void RotateRL(TreeNode parent){
TreeNode subR = root.right;
TreeNode subRL = subR.left;
int bf = subRL.bf;
//先右旋
RotateR(parent.right);
//再左旋
RotateL(parent);
if(bf == 1){
subRL.bf = 0;//不变的
subR.bf = 0;
parent.bf = -1;
}else if(bf == -1){
subRL.bf = 0;
subR.bf = 1;
parent.bf = 0;
}
}