目录
前言
主要内容为AVL树的插入操作(不包含重复值),主要分为四种情况:
- 右旋(Single Right Rotation)
- 左旋(Single Left Rotation)
- 先左旋后右旋(Left-Right Rotation)
- 先右旋后左旋(Left-Right Rotation)
一、AVL树简介
AVL树本质上是一颗平衡二叉树,但是它又具有以下特点:
- 它是一棵空树或它的左右两个子树的高度差的绝对值不超过1
- 左右两个子树都是一棵平衡二叉树
AVL树可视化网站:https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
平衡因子bf
AVL树的每个节点都有一个平衡因子(Balance Factor)
节点n的平衡因子表示为:n的左子树的高度 - n的右子树的高度
一棵AVL树的平衡因子的取值只能是:-1、0、1,否则AVL树不平衡,需要恢复平衡。不平衡的时候平衡因子只能为-2或者2.
二、AVL树的插入操作(不包含重复值)
1.找到要插入的位置(和普通的二叉搜索树一样)
递归插入:
- 如果要插入的数据比当前节点大,则插入到右子树
- 如果要插入的数据比当前节点小,则插入到左子树
AVLTree<T> newAVL = new AVLTree<>(value, leftNode, rightNode);
// Ensure input is not null.
if (value == null)
throw new IllegalArgumentException("Input cannot be null");
if (element.compareTo(value) > 0) {
newAVL.rightNode = rightNode.insert(element);
} else if (element.compareTo(value) < 0) {
newAVL.leftNode = leftNode.insert(element);
} else {
return this;
}
2.平衡化
插入数据后,可能会使得AVL树不平衡,主要分为下列四种情况:
- 插入位置为不平衡点的左节点的左子树(此时不平衡点的bf=2,其左节点的bf=1)
- 插入位置为不平衡点的右节点的右子树(此时不平衡点的bf=-2,其右节点的bf=-1)
- 插入位置为不平衡点的左节点的右子树(此时不平衡点的bf=2,其左节点的bf=-1)
- 插入位置为不平衡点的右节点的左子树(此时不平衡点的bf=-2,其右节点的bf=1)
情况1:右旋(Single Right Rotation)
插入位置(A)为不平衡点的左节点的左子树(此时不平衡点的bf=2,其左节点的bf=1)
情况2:左旋(Single Left Rotation)
插入位置(N)为不平衡点的右节点的右子树(此时不平衡点的bf=-2,其右孩子的bf=-1)
情况3:先左旋后右旋(Left-Right Rotation)
插入位置(B1)为不平衡点的左节点的右子树(此时不平衡点的bf=2,其左节点的bf=-1)
左旋:
右旋:
情况4:先右旋后左旋(Left-Right Rotation)
插入位置为不平衡点的右节点的左子树(此时不平衡点的bf=-2,其右节点的bf=1)
和先左旋后右旋过程对称,故省略。
相关代码
public AVLTree<T> insert(T element) {
AVLTree<T> newAVL = new AVLTree<>(value, leftNode, rightNode);
// Ensure input is not null.
if (value == null)
throw new IllegalArgumentException("Input cannot be null");
if (element.compareTo(value) > 0) {
newAVL.rightNode = rightNode.insert(element);
} else if (element.compareTo(value) < 0) {
newAVL.leftNode = leftNode.insert(element);
} else {
return this;
}
//4 cases for imbalance
int balanceFactor = newAVL.getBalanceFactor();
if(balanceFactor == 2){
if (((AVLTree<T>) newAVL.leftNode).getBalanceFactor() < 0) {
newAVL.leftNode = ((AVLTree<T>) newAVL.leftNode).leftRotate();
}
return newAVL.rightRotate();
}
else if(balanceFactor == -2){
if (((AVLTree<T>) newAVL.rightNode).getBalanceFactor() > 0) {
newAVL.rightNode = ((AVLTree<T>) newAVL.rightNode).rightRotate();
}
return newAVL.leftRotate();
}
return newAVL;
}
/**
* Conducts a left rotation on the current node.
*
* @return the new 'current' or 'top' node after rotation.
*/
public AVLTree<T> leftRotate() {
Tree<T> newParent = this.rightNode;
Tree<T> newRightOfCurrent = newParent.leftNode;
this.rightNode = newRightOfCurrent;
newParent.leftNode = this;
return (AVLTree<T>) newParent;
}
/**
* Conducts a right rotation on the current node.
*
* @return the new 'current' or 'top' node after rotation.
*/
public AVLTree<T> rightRotate() {
Tree<T> newParent = this.leftNode;
Tree<T> newLeftOfCurrent = newParent.rightNode;
this.leftNode = newLeftOfCurrent;
newParent.rightNode = this;
return (AVLTree<T>) newParent; // Change to return something different
}