数据结构-AVL树(平衡二叉树)

概述:

为了达到结点的平衡,AVL树引入的四种旋转操作

  1. 左孩子的左子树太高:以当前结点为根节点进行右旋操作
    在这里插入图片描述
child=node.left;
node.left=child.right;
child.right=node;
//更新node,child的高度
  1. 右孩子的右子树太高:以当前结点为根节点进行左旋操作
    在这里插入图片描述
child=node.right;
node.right=child.left;
child.left=node;
//更新node,child的高度
  1. 左孩子的右子树太高:左平衡操作:先以当前节点的左孩子为根节点进行左旋,在以当前节点为根节点进行右旋
    在这里插入图片描述
  2. 右孩子的左子树太高了:右平衡操作:先以右孩子为根节点进行右旋,在以当前节点为根节点进行左旋。
    在这里插入图片描述

模拟插入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);

    }
}

猜你喜欢

转载自blog.csdn.net/Fly_Fly_Zhang/article/details/94973710