AVL树详解
相关文章链接:
观前提示:
本文所使用的Eclipse版本为Photon Release (4.8.0),IDEA版本为ultimate 2019.1,JDK版本为1.8.0_141,Tomcat版本为9.0.12。
1. 简介
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。
特点
-
本身首先是一棵二叉搜索树。
-
带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
平衡因子: 某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。
2. 插入
这里只介绍插入节点后破坏平衡所做的旋转操作。
2.1 单向右旋平衡处理LL
在左子树(L)的左孩子(L)插入节点失衡,需要进行单向右旋平衡处理LL。
2.2 单向左旋平衡处理RR
在右子树(R)的右孩子(R)插入节点失衡,需要进行单向左旋平衡处理RR。
2.3 双向旋转(先左后右)平衡处理LR
在左子树(L)的右孩子(R)插入节点失衡,需要进行双向旋转(先左后右)平衡处理LR。
2.4 双向旋转(先右后左)平衡处理RL
在右子树(R)的左孩子(L)插入节点失衡,需要进行双向旋转(先右后左)平衡处理RL。
3. 删除
AVL树删除操作步骤如下
-
搜索给定的key,确定其是否在树中。
-
如果不在树中,返回null;如果在树中,执行标准的BST删除操作,并返回该删除的结点。
-
检查被删除结点的所有祖先结点是否平衡,如果不平衡,则执行重平衡操作。
BST删除操作三种情况
-
当该节点为叶子节点,则让该节点的父节点指向其变为NULL,然后释放节点。
-
当该节点不是叶子节点,但左子树或者右子树为空,则:
(1)若左子树为空,则让该节点父节点指向其右节点。
(2)若右子树为空,则让该节点父节点指向其左节点。 -
当该节点不是叶子节点,且左子树和右子树都不为空,则:
(1)在该节点的左子树中找到最大节点Lmax(该节点必然是一个叶子节点)或者右子树中的最小节点Rmin,取出节点的值value,并删除该节点。
(2)将value的值赋到要删除的节点。
4 java代码例子
AVL树 AVLTree.java
package TestTree.AVL;
public class AVLTree {
private Integer root;
private AVLTree left;
private AVLTree right;
private Integer height;
public AVLTree(Integer root) {
this.root = root;
}
public Integer getRoot() {
return root;
}
public void setRoot(Integer root) {
this.root = root;
}
public AVLTree getLeft() {
return left;
}
public void setLeft(AVLTree left) {
this.left = left;
}
public AVLTree getRight() {
return right;
}
public void setRight(AVLTree right) {
this.right = right;
}
public Integer getHeight() {
return height;
}
/**
* 获取指定节点深度
* @param node
* @return
*/
public static Integer getHeight(AVLTree node){
if(node == null){
return 0;
}
return node.height;
}
public void setHeight(Integer height) {
this.height = height;
}
/**
* 指定节点深度赋值
* @param node
* @param height
*/
public static void setHeight(AVLTree node, Integer height) {
if(node == null){
return;
}
node.height = height;
}
/**
* 获取最小节点
* @param node
* @return
*/
public static AVLTree getMinNode(AVLTree node){
if(node != null && node.getLeft() == null){
return node;
}
return getMinNode(node.getLeft());
}
}
树操作工具类 TreeOperateUtil.java
package TestTree.AVL;
/**
* 树操作工具类
* @author jjy
* @date 2020-10-19
*/
public class TreeOperateUtil {
/**
* 插入节点
* @param node
* @param data
* @return
*/
public static AVLTree insert(AVLTree node, int data){
// 根节点没有数据,直接插入
if(node == null || node.getRoot() == null){
node = new AVLTree(data);
node.setHeight(1);
return node;
}
if(node.getRoot() > data){
node.setLeft(insert(node.getLeft(), data));
} else {
node.setRight(insert(node.getRight(), data));
}
// 更新深度
node.setHeight(1 + Math.max(AVLTree.getHeight(node.getLeft()), AVLTree.getHeight(node.getRight())));
int balanceFactor = getBalanceFactor(node);
// LL
if(balanceFactor == 2 && getBalanceFactor(node.getLeft()) > 0 ){
System.out.println("-------------LL旋转-------------");
return LLRotate(node);
}
// LR
if(balanceFactor == 2 && getBalanceFactor(node.getLeft()) < 0){
System.out.println("-------------LR旋转-------------");
return LRRotate(node);
}
// RR
if(balanceFactor == -2 && getBalanceFactor(node.getRight()) < 0){
System.out.println("-------------RR旋转-------------");
return RRRotate(node);
}
// RL
if(balanceFactor == -2 && getBalanceFactor(node.getRight()) > 0){
System.out.println("-------------RL旋转-------------");
return RLRotate(node);
}
return node;
}
/**
* 删除节点
* @param node
* @param data
* @return
*/
public static AVLTree remove(AVLTree node, int data){
if(node == null){
return null;
}
if(node.getRoot() > data){
node.setLeft(remove(node.getLeft(), data));
} else if( node.getRoot() < data){
node.setRight(remove(node.getRight(), data));
} else {
if(node.getLeft() == null) {
// 没有左子树
node = node.getRight();
} else if(node.getRight() == null) {
// 没有右子树
node = node.getLeft();
} else {
// 左右子树均不为空,取右子树最小值(或者左子树最大值),替换当前要删除的节点
AVLTree minNode = AVLTree.getMinNode(node.getRight());
node.setRight(remove(node.getRight(), minNode.getRoot