java AVL树增删查模拟
一、AVL树概念
- AVL树就是平衡二叉查询树,每个节点的左子树和右子树高度最多相差1,这个差值就是平衡因子
- 树的左右子树都是AVL树。
二、AVL树初始化
2.1 AVLNode属性
public class AVLNode {
public AVLNode parent;
public AVLNode left;
public AVLNode right;
public int height;
public int value;
public AVLNode(AVLNode parent, AVLNode left, AVLNode right, int value) {
this.parent = parent;
this.left = left;
this.right = right;
this.height = 1;
this.value = value;
}
}
2.2 AVLTree属性
public class AVLTree {
public AVLNode root;
}
三、影响AVL平衡的因素
-
主要以下四种情况
-
LL 是操作节点的左子树的高度-右子树的高度>1,且操作节点的左节点左子树高度>=右子树高度,根据此种情况,需要对操作节点右旋
-
LR 是操作节点的左子树的高度-右子树的高度>1,且操作节点的左节点左子树高度<右子树高度,根据此种情况,需要对操作节点左节点左旋后,在对操作节点右旋
-
RR是操作节点的左子树的高度-右子树的高度<-1,且操作节点的左节点左子树高度<=右子树高度,根据此种情况,需要对操作节点左旋
-
RL是操作节点的左子树的高度-右子树的高度<-1,且操作节点的左节点左子树高度>右子树高度,根据此种情况,需要对操作节点右节点右旋后,在对操作节点左旋
四、AVL增加节点
4.1 增加节点
- 判断插入值得大小,插入后,查询当前左右节点的平衡因子,如果平衡因子不为1,0,-1,则需要调平,平衡因子 = 左子树高度-右子树高度
- 如果平衡因子>1,体现为L,继续判断操作节点的左节点的高度大小,如果左节点的左高度>=右高度,则体现为L,最终体现为LL
- 如果平衡因子>1,体现为L,继续判断操作节点的左节点的高度大小,如果左节点的左高度<右高度,则体现为R,最终体现为LR
- 如果平衡因子<-1,体现为R,继续判断操作节点的右节点的高度大小,如果右节点的左高度<=右高度,则体现为R,最终体现为RR
- 如果平衡因子<-1,体现为R,继续判断操作节点的右节点的高度大小,如果右节点的左高度>右高度,则体现为L,最终体现为RL
4.2 增加节点代码
public void add(int value) {
if (root == null) {
root = new AVLNode(null, null, null, value);
return;
}
addNode(value, root);
}
private AVLNode addNode(int value, AVLNode node) {
if (node == null) {
return new AVLNode(null, null, null, value);
} else {
if (value > node.value) {
node.right = addNode(value, node.right);
node.right.parent = node;
} else if (value < node.value) {
node.left = addNode(value, node.left);
node.left.parent = node;
} else {
return node;
}
// 开始设置高度
resetHeight(node);
// 开始调整结构
return rebalance(node);
}
}
private AVLNode rebalance(AVLNode node) {
// 判断平衡因子
if (height(node.left) - height(node.right) > 1) {
if (height(node.left.left) < height(node.left.right)) {
// 先左旋
rolateLeft(node.left);
}
return rolateRight(node);
} else if (height(node.left) - height(node.right) < -1) {
if (height(node.right.left) > height(node.right.right)) {
// node右旋
rolateRight(node.right);
}
return rolateLeft(node);
}
return node;
}
private void resetHeight(AVLNode node) {
node.height = Math.max(height(node.left), height(node.right)) + 1;
}
private AVLNode rolateLeft(AVLNode node) {
AVLNode right = node.right;
AVLNode left = right.left;
AVLNode parent = node.parent;
node.right = left;
if (left != null) {
left.parent = node;
}
node.parent = right;
right.parent = parent;
right.left = node;
if (parent == null) {
root = right;
} else if (parent.left == node) {
parent.left = right;
} else if (parent.right == node) {
parent.right = right;
}
resetHeight(node);
resetHeight(right);
return right;
}
private AVLNode rolateRight(AVLNode node) {
AVLNode left = node.left;
AVLNode parent = node.parent;
AVLNode right = left.right;
left.right = node;
node.left = right;
if (right != null) {
right.parent = node;
}
node.parent = left;
left.parent = parent;
if (parent == null) {
root = left;
} else if (parent.left == node) {
parent.left = left;
} else if (parent.right == node) {
parent.right = left;
}
resetHeight(node);
resetHeight(left);
return left;
}
private int height(AVLNode node) {
return node == null ? 0 : node.height;
}
五、AVL删除节点
5.1 删除节点
- 首先找到删除节点
- 判断删除节点有几个子节点,一个或者没有,则直接删除
- 如果有两个子节点,删除该节点的后继节点,然后用后继节点内容代替当前节点内容
- 调整高度后,判断平衡因子并调平
5.2 删除节点代码
public void delete(int value) {
if (root == null) {
return;
}
delete(value, root);
}
private AVLNode delete(int value, AVLNode node) {
if (node == null) {
return null;
}
if (value > node.value) {
node.right = delete(value, node.right);
} else if (value < node.value) {
node.left = delete(value, node.left);
} else {
// 判断当前node有几个节点
if (node.left == null && node.right == null) {
// 直接删除当前节点
return null;
} else if (node.left == null) {
node.right.parent = node.parent;
return node.right;
} else if (node.right == null) {
node.left.parent = node.parent;
return node.left;
} else {
// 找到后继节点
AVLNode avlNode = findSussorNode(node);
// 删除后继节点
AVLNode newNode = delete(avlNode.value, node);
node.value = avlNode.value;
return newNode;
}
}
resetHeight(node);
return rebalance(node);
}
private AVLNode findSussorNode(AVLNode node) {
AVLNode right = node.right;
while (right.left != null) {
right = right.left;
}
return right;
}