概述:
为了达到结点的平衡,AVL树引入的四种旋转操作
- 左孩子的左子树太高:以当前结点为根节点进行右旋操作
child=node.left;
node.left=child.right;
child.right=node;
//更新node,child的高度
- 右孩子的右子树太高:以当前结点为根节点进行左旋操作
child=node.right;
node.right=child.left;
child.left=node;
//更新node,child的高度
- 左孩子的右子树太高:左平衡操作:先以当前节点的左孩子为根节点进行左旋,在以当前节点为根节点进行右旋
- 右孩子的左子树太高了:右平衡操作:先以右孩子为根节点进行右旋,在以当前节点为根节点进行左旋。
模拟插入1-10的十个树的插入平衡旋转图解。
注意,调整平衡都是从底层开始。任何一个节点左右子树的层数差大于1就需要调整。
AVL代码演示:
package com.AdvancedDataStructure.AVLTree;
/**
* @Created with IntelliJ IDEA
* @Description: AVL代码演示
* @Package: com.AdvancedDataStructure.BSTTree
* @author: FLy-Fly-Zhang
* @Date: 2019/7/3
* @Time: 21:05
*/
/*
* AVL是不是一颗二叉搜索树
* AVL在插入过程中,最多旋转两次
* AVL在删除过程中,最差的情况下,需要旋转的次数是多少次? O(log2N)
* AVL树为了保持平衡,而做的旋转操作过多,当数据量大的时候,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 AVL <T extends Comparable<T>>{
private AVLNode<T> 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 height(AVLNode<T> node){
return node==null?0:node.getHeight();
}
private int maxHeight(AVLNode<T> node1,AVLNode<T> node2){
int l=height(node1);
int r=height(node2);
return l>r?l:r;
}
public void insert(T data){
this.root=insert(this.root,data);
}
/**
* 以参数root为起始结点,搜索一个合适的位置添加结点,
* 然后把子树的根结点返回。
* @param root
* @param data
* @return
*/
private AVLNode<T> insert(AVLNode<T> root, T data) {
if(root==null)
return new AVLNode<T>(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 if(root.getData().compareTo(data)<0){
root.setRight(insert(root.getRight(),data));
//右子树高于左子树
if(height(root.getRight())-height((root.getLeft()))>1){
//右孩子的右子树太高,右旋
if(height(root.getRight().getLeft())<=height(root.getRight().getRight())){
root=leftRotate(root);
}else{//右孩子的左子树太高,右平衡
root=rightBalance(root);
}
}
}
//递归回溯过程中,更新结点的高度值
root.setHeight(maxHeight(root.getLeft(),root.getRight())+1);
return root;
}
public void remove(T data){
this.root=remove(this.root,data);
}
/**
* 递归删除
* @param root
* @param data
* @return
*/
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));
if(root.getRight().getHeight()-root.getLeft().getHeight()>1){
if(height(root.getRight().getRight())>height(root.getRight().getLeft())){
root=rightRotate(root);
}else{
root=rightBalance(root);
}
}
}else if(root.getData().compareTo(data)<0){
root.setRight(remove(root.getRight(),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{
if(root.getLeft()!=null&&root.getRight()!=null){
AVLNode<T> pre;
//删除层数多的子树,这样可以避免删除带来的旋转操作,提高效率
if(root.getLeft().getHeight()>root.getRight().getHeight()){
//前驱删除
pre=root.getLeft();
while(pre.getRight()!=null){
pre=pre.getRight();
}
root.setData(pre.getData());
//递归删除元素
root.setLeft(remove(root.getLeft(),data));
}else{
//后继删除
pre=root.getRight();
while(pre.getLeft()!=null){
pre=pre.getLeft();
}
root.setData(pre.getData());
root.setRight(remove(root.getRight(),data));
}
//最底层不用变高度
}else if(root.getLeft()!=null){
return root.getLeft();
}else if(root.getRight()!=null){
return root.getRight();
}else{
return null;
}
}
root.setHeight(maxHeight(root.getLeft(),root.getRight()));
return root;
}
class BSTNode<T>{
int data;
BSTNode left;
BSTNode right;
}
private boolean b=true;
//判断一个BST树是不是平衡二叉树
public boolean isAVL(BSTNode<T> root){
isAVL(root,1);
return b;
}
private int isAVL(BSTNode<T> root,int i) {
if(root==null)
return 0;
int l=isAVL(root.left,1);
int r=isAVL(root.right,1);
if(Math.abs(l-r)>1){
b=false;
}
return l>r?l+1:r+1;
}
}
public class AVLDemo {
public static void main(String[] args) {
AVL<Integer> avl=new AVL();
long begin=0,end=0;
begin=System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
avl.insert(i);
}
end=System.currentTimeMillis();
System.out.println(end-begin);
}
}