1、AVL平衡二叉树概念
平衡二叉树是一种高度平衡的二叉排列树,将二叉树上的结点的左子树深度减去右子树的值称为平衡因子BF,那么一颗子树的平衡因子则可以分为LH(1),EH(0),RH(-1)。只要二叉树上的一个结点的平衡因子的绝对值大于1则该二叉树就是不平衡的
2、左旋介绍
当一结点的平衡因子的右子树深度比左子树深度大1以上时,且以该结点为顶点的树为最小不平衡子树,我们可以对当前结点为顶点的树进行左旋,可以获得一个平衡的二叉树。
进行左旋的步骤:
1、T节点的右子树指向R结点的左子树
2、R结点的左子树指向T结点
3、R结点称为该树的顶点
实现代码:
TreeNode leftRotate(TreeNode node) {
TreeNode rightNode = node.right;
node.right = rightNode.left;
rightNode.left = node;
return rightNode;
}
3、右旋介绍
当一结点的平衡因子的左子树深度比右子树深度大1以上时,且以该结点为顶点的树为最小不平衡子树,我们可以对当前结点为顶点的树进行右旋,可以获得一个平衡的二叉树。
进行右旋的步骤:
1、T节点的右子树指向L结点的右子树
2、L结点的右子树指向T结点
3、L结点称为该树的顶点
实现代码:
TreeNode rightRotate(TreeNode node) {
TreeNode leftNode = node.left;
node.left = leftNode.right;
leftNode.right = node;
return leftNode;
}
3、双旋介绍
需要旋转的结点情况分为LL、RR、LR、RL,当为RL和LR时需要进行双旋转,LR时需要先左旋后右旋,RL时需要先右旋后左旋。因为我们使用的是BF因子记录每个节点的左右子树平衡是否平衡,所以每次旋转时都需要更新BF因子。
因为我们使用递归进行插入和删除,所以当判断某个结点的平衡因子时候,默认该结点的子树的平衡因子已经进行过更新,但该结点的平衡因子没有进行更新。
LL计算需要更新的bf因子:
当前结点的BF为LH时,且左子树增高,则需要对左子树进行左子树平衡。并且当前结点的左孩子的BF为LH时则为LL型,需要进行右旋并且更新bf因子。
计算步骤:
1、在右旋之前,因为L结点的BF为LH,可得:
2、在右旋之前,因为T结点的BF为LH,并且左子树增高,所以BF现在应该为2,可得:
因为LL>LR,所以
3、所以可以推出:
4、所以在右旋后可以知道:
实现代码:
TreeNode leftBalance(TreeNode node) {
......
case 1:
node.bf = EH;
leftNode.bf = EH;
res = rightRotate(node);
break;
......
}
TreeNode insert(TreeNode node, int num, int idx) {
.......
if (node.data > num || node.data == num) {
node.left = insert(node.left, num, idx);
if (taller) {
switch (node.bf) {
case 1:
taller = false;
return leftBalance(node);
case 0:
node.bf = LH;
taller = true;
return node;
case -1:
node.bf = EH;
taller = false;
return node;
}
}
......
}
LR计算需要更新的bf因子:
当前结点的BF为LH时,且左子树增高,则需要对左子树进行左子树平衡。并且当前的左孩子的右子树比左子树高,则当前的树为LR型。
LR型进行平衡需要先对L结点进行左旋,然后再对T结点进行右旋,平衡后的树的结构如下图。
计算步骤:
1、在平衡前,从LR结点为LH可得:
2、在平衡前,从L结点为RH可得:
3、在平衡前,由T结点为LH,且左子树增高可得:
4、根据上列公式,可得平衡后有:
5、可以推出平衡后:
实现代码:
TreeNode leftBalance(TreeNode node) {
......
switch (leftNode.bf) {
......
case -1:
leftRight = leftNode.right;
switch (leftRight.bf) {
case -1:
node.bf = EH;
leftNode.bf = LH;
break;
case 1:
leftNode.bf = EH;
node.bf = RH;
break;
case 0:
leftNode.bf = EH;
node.bf = EH;
break;
}
leftRight.bf = EH;
node.left = leftRotate(leftNode);
res = rightRotate(node);
break;
}
return res;
}
TreeNode insert(TreeNode node, int num, int idx) {
.......
if (node.data > num || node.data == num) {
node.left = insert(node.left, num, idx);
if (taller) {
switch (node.bf) {
case 1:
taller = false;
return leftBalance(node);
.......
}
}
} else {
........
}
return node;
}
4、AVL树插入
自平衡二叉搜索树插入和二叉搜索树插入操作差不多,但是插入之后需要判断是否需要进行旋转调整。
需要调整的情况(举例插入到左子树):
如果左子树深度增高(taller),并且当前结点的BF因子为LH,则需要进行左平衡操作
实现代码:
TreeNode insert(TreeNode node, int num, int idx) {
if (root == null) {
root = new TreeNode(null, null, num, idx, EH);
return root;
}
if (node == null) {
taller = true;
return new TreeNode(null, null, num, idx, EH);
} else {
if (node.data == num && node.idx == idx) {
System.out.println("已存在当前节点");
taller = false;
return node;
}
if (node.data > num || node.data == num) {
node.left = insert(node.left, num, idx);
if (taller) {
switch (node.bf) {
case 1:
taller = false;
return leftBalance(node);
case 0:
node.bf = LH;
taller = true;
return node;
case -1:
node.bf = EH;
taller = false;
return node;
}
}
} else {
node.right = insert(node.right, num, idx);
if (taller) {
switch (node.bf) {
case 1:
node.bf = EH;
taller = false;
return node;
case 0:
node.bf = RH;
taller = true;
return node;
case -1:
taller = false;
return rightBalance(node);
}
}
}
}
return node;
}
5、AVL树删除
自平衡二叉搜索树插入和二叉搜索树删除操作差不多,但是删除之后需要判断是否需要进行旋转调整。
需要调整的情况(举例删除节点到左子树):
如果左子树深度降低(shorter),并且当前结点的BF因子为RH,则需要进行右平衡操作。
实现代码:
TreeNode delete(TreeNode node, int num, int idx) {
if (node == null) {
return null;
} else {
if (node.data == num && node.idx == idx) {
//找到要删除的节点
if (node.left == null && node.right != null) {
shorter = true;
return node.right;
} else if (node.left != null && node.right == null) {
shorter = true;
return node.left;
} else if (node.left != null && node.right != null) {
//找到左子树的最大数值节点
TreeNode left = node.left;
while (left.right != null) {
left = left.right;
}
//从当前的左子树中删除该节点
node = delete(node, left.data, left.idx);
//替换当前节点
node.data = left.data;
node.idx = left.idx;
shorter = true;
return node;
} else {
shorter = true;
return null;
}
} else if (node.data > num || node.data == num) {
node.left = delete(node.left, num, idx);
if (shorter) {
//左子树高度减少1
switch (node.bf) {
case 1:
node.bf = EH;
shorter = true;
return node;
case 0:
node.bf = RH;
shorter = false;
return node;
case -1:
shorter = false;
TreeNode treeNode = rightBalance(node);
if (node == root) root = treeNode;
return treeNode;
}
}
} else {
node.right = delete(node.right, num, idx);
if (shorter) {
switch (node.bf) {
case 1:
shorter = false;
TreeNode treeNode = leftBalance(node);
if (node == root) root = treeNode;
return treeNode;
case 0:
node.bf = LH;
shorter = false;
return node;
case -1:
node.bf = EH;
shorter = true;
return node;
}
}
}
}
return node;
}
6、全部代码
class AVLTree {
public static final Integer LH = 1;
public static final Integer EH = 0;
public static final Integer RH = -1;
boolean taller;
boolean shorter;
class TreeNode {
TreeNode left, right;
Integer data;
Integer idx;
Integer bf;
public TreeNode(TreeNode left, TreeNode right, Integer data, Integer idx, Integer bf) {
this.left = left;
this.right = right;
this.data = data;
this.idx = idx;
this.bf = bf;
}
}
TreeNode root;
public AVLTree() {
root = null;
taller = false;
shorter = false;
}
TreeNode rightRotate(TreeNode node) {
TreeNode leftNode = node.left;
node.left = leftNode.right;
leftNode.right = node;
return leftNode;
}
TreeNode leftRotate(TreeNode node) {
TreeNode rightNode = node.right;
node.right = rightNode.left;
rightNode.left = node;
return rightNode;
}
TreeNode leftBalance(TreeNode node) {
TreeNode res = null;
TreeNode leftNode = node.left;
TreeNode leftRight;
switch (leftNode.bf) {
case 1:
node.bf = EH;
leftNode.bf = EH;
res = rightRotate(node);
break;
case 0:
node.bf = LH;
leftNode.bf = RH;
res = rightRotate(node);
break;
case -1:
leftRight = leftNode.right;
switch (leftRight.bf) {
case -1:
node.bf = EH;
leftNode.bf = LH;
break;
case 1:
leftNode.bf = EH;
node.bf = RH;
break;
case 0:
leftNode.bf = EH;
node.bf = EH;
break;
}
leftRight.bf = EH;
node.left = leftRotate(leftNode);
res = rightRotate(node);
break;
}
return res;
}
TreeNode rightBalance(TreeNode node) {
TreeNode res = null;
TreeNode rightNode = node.right;
TreeNode rightLeft;
switch (rightNode.bf) {
case 1:
rightLeft = rightNode.left;
switch (rightLeft.bf) {
case -1:
node.bf = LH;
rightNode.bf = EH;
break;
case 1:
node.bf = EH;
rightNode.bf = RH;
break;
case 0:
node.bf = EH;
rightNode.bf = EH;
break;
}
rightLeft.bf = EH;
node.right = rightRotate(rightNode);
res = leftRotate(node);
break;
case 0:
node.bf = RH;
rightNode.bf = LH;
res = leftRotate(node);
break;
case -1:
node.bf = EH;
rightNode.bf = EH;
res = leftRotate(node);
break;
}
return res;
}
TreeNode insert(TreeNode node, int num, int idx) {
if (root == null) {
root = new TreeNode(null, null, num, idx, EH);
return root;
}
if (node == null) {
taller = true;
return new TreeNode(null, null, num, idx, EH);
} else {
if (node.data == num && node.idx == idx) {
System.out.println("已存在当前节点");
taller = false;
return node;
}
if (node.data > num || node.data == num) {
node.left = insert(node.left, num, idx);
if (taller) {
switch (node.bf) {
case 1:
taller = false;
return leftBalance(node);
case 0:
node.bf = LH;
taller = true;
return node;
case -1:
node.bf = EH;
taller = false;
return node;
}
}
} else {
node.right = insert(node.right, num, idx);
if (taller) {
switch (node.bf) {
case 1:
node.bf = EH;
taller = false;
return node;
case 0:
node.bf = RH;
taller = true;
return node;
case -1:
taller = false;
return rightBalance(node);
}
}
}
}
return node;
}
TreeNode delete(TreeNode node, int num, int idx) {
if (node == null) {
return null;
} else {
if (node.data == num && node.idx == idx) {
//找到要删除的节点
if (node.left == null && node.right != null) {
shorter = true;
return node.right;
} else if (node.left != null && node.right == null) {
shorter = true;
return node.left;
} else if (node.left != null && node.right != null) {
//找到左子树的最大数值节点
TreeNode left = node.left;
while (left.right != null) {
left = left.right;
}
//从当前的左子树中删除该节点
node = delete(node, left.data, left.idx);
//替换当前节点
node.data = left.data;
node.idx = left.idx;
shorter = true;
return node;
} else {
shorter = true;
return null;
}
} else if (node.data > num || node.data == num) {
node.left = delete(node.left, num, idx);
if (shorter) {
//左子树高度减少1
switch (node.bf) {
case 1:
node.bf = EH;
shorter = true;
return node;
case 0:
node.bf = RH;
shorter = false;
return node;
case -1:
shorter = false;
TreeNode treeNode = rightBalance(node);
if (node == root) root = treeNode;
return treeNode;
}
}
} else {
node.right = delete(node.right, num, idx);
if (shorter) {
switch (node.bf) {
case 1:
shorter = false;
TreeNode treeNode = leftBalance(node);
if (node == root) root = treeNode;
return treeNode;
case 0:
node.bf = LH;
shorter = false;
return node;
case -1:
node.bf = EH;
shorter = true;
return node;
}
}
}
}
return node;
}
void infixOrder() {
infixOrder(root);
System.out.println();
}
//中序遍历
void infixOrder(TreeNode node) {
if (node == null) {
return;
}
infixOrder(node.left);
System.out.print(node.data + " ");
infixOrder(node.right);
}
Integer search(int target) {
if (root == null) return -1;
TreeNode node = root;
while (node != null) {
if (node.data < target) {
node = node.right;
} else if (node.data > target) {
node = node.left;
} else return node.idx;
}
return -1;
}
}