AVL树本质上还是一棵二叉搜索树,AVL = BST + 平衡操作
所以它的特点是:
1.本身首先是一棵二叉搜索树。
2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
3.树中的每个左子树和右子树都是AVL树
也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。
为何引入AVL:
对于一般的二叉搜索树(Binary Search Tree),其各操作的时间复杂度 O(log2n) 。但是,在某些极端的情况下(如在插入的序列是有序的时),二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。而AVL树会不断调整自身来达到左右子树高度差值不会超过1,这样就保证了其各个操作的时间复杂度保持在 O(log2n) 。
注:
1、AVL树是不是平衡树?平衡是什么意思?
是平衡树,平衡:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1
2、AVL是不是搜索树?
是搜索树,AVL = BST + 平衡操作,AVL具有BST全部特性。
3、AVL的几种旋转
AVL有四中旋转操作。
4、AVL树时间复杂度。
一棵AVL树有N个节点,高度可以保持在log2n,插入/删除/查找的时间复杂度也是log2n.
5、AVL树最差情况下,增删查需要旋转多少次?O(log2n)次
O(log2n)次
平衡操作:节点的左右子树的高度差不能超过1,为了维持节点平衡 引入的四种节点旋转操作
1、左孩子的左子树太高 ----右旋转操作
child = node.left;
node,left = child.right;
child.right = node;
node和child的高度要更新!
2、右孩子的右子树太高 -----左旋转操作
child = node.right;
node.right = child.left;
child.left = node;
node和child的高度要更新
3、左孩子的右子树太高-----左平衡操作
孩子节点先左旋,然后再右旋
4、右孩子的左子树太高-----右平衡操作
孩子节点先右旋,然后再左旋
AVL树增加删除代码:
节点的定义:
class AVLNode<T extends Comparable<T>>{
private T data;
private AVLNode<T> left;
private AVLNode<T> right;
private int height; // 保存当前节点的高度值
public AVLNode(T data, AVLNode<T> left, AVLNode<T> right, int height) {
this.data = data;
this.left = left;
this.right = right;
this.height = height;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public AVLNode<T> getLeft() {
return left;
}
public void setLeft(AVLNode<T> left) {
this.left = left;
}
public AVLNode<T> getRight() {
return right;
}
public void setRight(AVLNode<T> right) {
this.right = right;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
完整代码:
class AVLTree<T extends Comparable<T>>{
private AVLNode<T> root;
public AVLTree() {
this.root = null;
}
/**
* 递归实现AVL树的插入操作
* AVL最差的情况,最差的情况下要旋转O(lgn)
* @param data
*/
public void insert(T data){
this.root = insert(this.root, data);
}
private AVLNode<T> insert(AVLNode<T> root, T data) {
if(root == null){
return new AVLNode<>(data, null, null, 1);
}
if(root.getData().compareTo(data) > 0){
root.setLeft(insert(root.getLeft(), data));
// 左子树太高
if(height(root.getLeft()) - height(root.getRight()) > 1){
// 左孩子的左子树太高
if(height(root.getLeft().getLeft())
>= height(root.getLeft().getRight())){
root = rightRotate(root);
} else {
// 左孩子的右子树太高
root = leftBalance(root);
}
}
} else {
root.setRight(insert(root.getRight(), data));
// 右子树太高
if(height(root.getRight()) - height(root.getLeft()) > 1){
// 右孩子的右子树太高
if(height(root.getRight().getRight())
>= height(root.getRight().getRight())){
root = leftRotate(root);
} else {
// 右孩子的左子树太高
root = rightBalance(root);
}
}
}
root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
return root;
}
/**
* 递归实现AVL树的删除操作
* @param data
*/
public void remove(T data){
this.root = remove(this.root, data);
}
private AVLNode<T> remove(AVLNode<T> root, T data) {
if(root == null){
return null;
}
if(root.getData().compareTo(data) > 0){
root.setLeft(remove(root.getLeft(), data));
// #1
if(height(root.getRight()) - height(root.getLeft()) > 1){
if(height(root.getRight().getRight())
>= height(root.getRight().getLeft())){
// 右孩子的右子树太高
root = leftRotate(root);
} else {
// 右孩子的左子树太高
root = rightBalance(root);
}
}
} else if(root.getData().compareTo(data) < 0){
root.setRight(remove(root.getRight(), data));
// #2
if(height(root.getLeft()) - height(root.getRight()) > 1){
if(height(root.getLeft().getLeft())
>= height(root.getLeft().getRight())){
// 左孩子的左子树太高
root = rightRotate(root);
} else {
// 左孩子的右子树太高
root = leftBalance(root);
}
}
} else {
if(root.getLeft() != null && root.getRight() != null){
// #3
if(height(root.getLeft()) >= height(root.getRight())){
// 用前驱节点代替
AVLNode<T> pre = root.getLeft();
while(pre.getRight() != null){
pre = pre.getRight();
}
root.setData(pre.getData());
root.setLeft(remove(root.getLeft(), pre.getData()));
} else {
// 用后继节点代替
AVLNode<T> post = root.getRight();
while(post.getLeft() != null){
post = post.getLeft();
}
root.setData(post.getData());
root.setRight(remove(root.getRight(), post.getData()));
}
} else {
if(root.getLeft() != null){
return root.getLeft();
} else if(root.getRight() != null){
return root.getRight();
} else {
return null;
}
}
}
// #4 在递归回溯的过程中更新节点的高度值
root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
return root;
}
/**
* 以参数node为根节点进行左旋转操作,并把旋转后的子树的根节点返回
* @param node
* @return
*/
private AVLNode<T> leftRotate(AVLNode<T> node){
AVLNode<T> child = node.getRight();
node.setRight(child.getLeft());
child.setLeft(node);
node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
return child;
}
/**
* 以参数node为根节点进行右旋转操作,并把旋转后的子树的根节点返回
* @param node
* @return
*/
private AVLNode<T> rightRotate(AVLNode<T> node){
AVLNode<T> child = node.getLeft();
node.setLeft(child.getRight());
child.setRight(node);
node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
return child;
}
/**
* 以参数node为根节点进行左平衡操作,并把平衡后的子树的根节点返回
* @param node
* @return
*/
private AVLNode<T> leftBalance(AVLNode<T> node){
node.setLeft(leftRotate(node.getLeft()));
return rightRotate(node);
}
/**
* 以参数node为根节点进行右平衡操作,并把平衡后的子树的根节点返回
* @param node
* @return
*/
private AVLNode<T> rightBalance(AVLNode<T> node){
node.setRight(rightRotate(node.getRight()));
return leftRotate(node);
}
private int maxHeight(AVLNode<T> node1, AVLNode<T> node2){
int h1 = height(node1);
int h2 = height(node2);
return h1 > h2 ? h1 : h2;
}
private int height(AVLNode<T> node){
return node == null ? 0 : node.getHeight();
}
}