平衡二叉树(AVL树)的四种旋转操作的实现:
关于为什么要使用平衡二叉树,我们首先举个例子来说明BST树存在的问题:
如上图,给你一个数列[10,20,30,40],创建一颗二叉排序树(BST),我们就上图来分析BST树存在的问题:
1.左子树全部为空,从形式上来看,像是一个单链表
2.插入速度没有影响
3.查询速度降低(因为类似于这样的BST树,在查询时,不仅要依次比较,不能发挥BST树的优势,每次还需要比较左子树,查询速度比单链表还慢)
如何解决BST树存在的此类问题呢?
解决方案:使用平衡二叉树(AVL)
平衡二叉树(AVL树)的概念及其使用
AVL = BST +平衡
平衡:节点的左右子树的高度差不超过1
平衡二叉树(AVL):
1.AVL树节点的类型
/**
* AVL树的节点类型
* @param <T>
*/
class AVLNode<T extends Comparable<T>>{
private T data;
private int height; //用来记录当前节点的高度
private AVLNode<T> left;
private AVLNode<T> right;
public AVLNode(T data, int height) {
this.data = data;
this.height = height;
this.left=this.right=null;
}
public AVLNode(T data, int height, AVLNode<T> left, AVLNode<T> right) {
this.data = data;
this.height = height;
this.left = left;
this.right = right;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
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;
}
2.AVL树的建立
/**
* AVL树的类定义
*/
class AVL<T extends Comparable<T>>{
private AVLNode<T> root;
public AVL(){
this.root=null;
}
/**
* 获取节点node的左右子树高度差
*/
public int height(AVLNode<T> node){
return node ==null?0:node.getHeight();
}
/***
* 返回当前节点左右子树的高度最高值
*/
public int maxHeight(AVLNode<T> left,AVLNode<T> right){
return height(left)>height(right)?height(left):height(right);
}
3.AVL树的左旋操作
/**
* node 20
* AVL树的左旋操作 child 30 ===》 30
* x 50 20 50
* 右孩子的右子树太高
*/
private AVLNode<T> rotateLeft(AVLNode<T> node){
AVLNode<T> child = node.getRight();
//以孩子节点为根节点进行左旋操作
node.setRight(child.getLeft());
//将孩子节点的右孩子设为node节点的左孩子
child.setLeft(node);
//将node节点设为孩子节点的左孩子
node.setHeight(maxHeight(node.getLeft(),node.getRight())+1);
//更新以node节点为根节点的AVL树的高度
child.setHeight(maxHeight(child.getLeft(),child.getRight())+1);
//更新以child节点为根节点的AVL树的高度
return child;
//把旋转后的根节点返回
}
4.AVL树的右旋操作的实现
/** node 40 20
* AVL树的右旋操作 child 20 ==》 10 40
* 左孩子的左子树太高 10 x x
*/
private AVLNode<T> rotateRight(AVLNode<T> node){
AVLNode<T> child = node.getLeft();
//1.以child孩子为根节点,进行右旋操作
node.setLeft(child.getRight());
//将孩子节点的右孩子作为node节点的左孩子
child.setRight(node);
//将node节点设为孩子节点的右孩子
node.setHeight(maxHeight(node.getLeft(),node.getRight())+1);
//更新以node节点为根节点的AVL树的高度
child.setHeight(maxHeight(child.getLeft(),child.getRight())+1);
//更新以child节点为根节点的AVL树的高度
return child;
//把旋转后的根节点返回
}
5.AVL树的左-右旋转(左平衡)
/**
* AVL树的(左平衡)左--右旋转 40 左旋 40 右旋 30
* 20 ===》 30 =====》20 40
* 左孩子的右子树太高 30 20
*
* 先以20为根节点进行左旋转,再以30为根节点进行右旋转
*/
private AVLNode<T> leftBalance(AVLNode<T> node){
node.setLeft(rotateLeft(node.getLeft()));
return rotateRight(node);
}
6.AVL树的右-左旋转(右平衡)
/**
* AVL树的右平衡 右--左旋转20 右旋 20 左旋 30
* 40 =====》 30 =====》 20 40
* 右孩子的左子树过高 30 40
*
* 先以40为根节点进行右旋转,再以30为根节点进行左旋转
*/
private AVLNode<T> rightBalance(AVLNode<T> node){
node.setRight(rotateRight(node.getRight()));
return rotateLeft(node);
}