平衡二叉树

本文详细介绍了平衡二叉树(AVL树)的概念,它是一种左右子树高度差不超过1的二叉搜索树,确保了高效的插入、查找和删除操作。通过LL、RR、LR和RL四种旋转方式保持树的平衡。此外,代码展示了AVLTree的节点定义、高度计算、平衡调整以及插入、删除、查找等核心操作的实现。
摘要由CSDN通过智能技术生成

平衡二叉树

Balanced Binary Tree,左右子树高度差不超过1,因此能够保证很好的插入和查找效率

# 定义

  • 左右子树高度差不超过1

  • 左右子树也是平衡二叉树

  • 空二叉树是平衡二叉树

#实现

节点定义
package com.piziwang.tree.avltree;

/**
 * 平衡二叉树 Balance Binary Tree
 * @author PIZIWANG
 * @date 2022-05-05 21:37
 **/
public class AVLTree<T extends Comparable>{
    /**树的根节点*/
    AVLTreeNode<T> mRoot;

    /**
     * avltree节点,内部类
     */
    public  class AVLTreeNode<T extends Comparable>{
        public T key;
        int height;
        AVLTreeNode<T> left;
        AVLTreeNode<T> right;

        public AVLTreeNode(T key,  AVLTreeNode<T> left, AVLTreeNode<T> right) {
            this.key = key;
            this.left = left;
            this.right = right;
        }
    }


    /**
     * 获取树的高度
     * @return 树的高度
     */
    public int height(){
        return height(mRoot);
    }

    private int height(AVLTreeNode<T> tree) {
        if (tree != null) {
            return tree.height;
        }
        return 0;
    }

    /**
     *  获取两个数中较大的那一个
     */
    private int max(int x,int y){
        return x>y ? x : y;
    }


    /**
     * LL旋转是围绕"失去平衡的AVL根节点"进行的
     * @param k2 k2  失去平衡的根节点
     * @return {@link AVLTreeNode}<{@link T}>
     */
    private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2){
        AVLTreeNode<T> k1;
        k1 = k2.left;
        k2.left=k1.right;
        k1.right=k2;
        k2.height = max(height(k2.left),height(k2.right))+1;
        k1.height = max(height(k1.left), k2.height)+1;
        return k1;
    }

    /**
     *  RR旋转是围绕"失去平衡的AVL根节点"进行的
     * @param k1 k1  失去平衡的根节点
     * @return {@link AVLTreeNode}<{@link T}>
     */
    private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1){
        AVLTreeNode<T> k2;
        k2 = k1.right;
        k1.right=k2.left;
        k2.left=k1;
        k1.height = max(height(k1.left),height(k1.right))+1;
        k2.height = max(height(k2.right), k1.height)+1;
        return k2;
    }

    /**
     * LR失去平衡的情况,需要经过两次旋转才能让AVL树 1.围绕根节点左节点,RR, 2.围绕根节点 LL
     * @param k3 k1  失去平衡的根节点
     * @return {@link AVLTreeNode}<{@link T}>
     */
    private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3){
       k3.left = rightRightRotation(k3.left);
       return  leftLeftRotation(k3);
    }
    /**
     * Rl失去平衡的情况,需要经过两次旋转才能让AVL树 1.围绕根节点右节点,LL, 2.围绕根节点 RR
     * @param k1  失去平衡的根节点
     * @return {@link AVLTreeNode}<{@link T}>
     */
    private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1){
        k1.right = leftLeftRotation(k1.right);
        return  rightRightRotation(k1);
    }

    /**
     * 插入节点
     * @param key
     */
    public void insert(T key){
       mRoot= insert(mRoot,key);
    }

    public void insert(T []key){
        for (int i = 0; i < key.length; i++) {
            mRoot= insert(mRoot,key[i]);
        }
    }

    private  AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key) {
        if (tree == null) {
            tree = new AVLTreeNode<T>(key,null,null);
            if (tree==null) {
                System.out.println("create failed");
                return null;
            }
        }else {
            // 比较带插入值和当前值节点的大小
            int cmp = key.compareTo(tree.key);
            if (cmp < 0) {
                //待插入值小于当前值,插在左侧
                tree.left=insert(tree.left,key);
                //插入节点后,判断是否导致不平衡
                if(height(tree.left)-height(tree.right)==2){
                    if (key.compareTo(tree.left.key)<0) {
                        // 左左
                        tree = leftLeftRotation(tree);
                    }else {
                        // 左右
                        tree =  leftRightRotation(tree);
                    }
                }
            }else if (cmp>0) {
                //待插入值大于当前值,插在右侧
                tree.right = insert(tree.right, key);
                // 判断是否导致不平衡
                if(height(tree.right) - height(tree.left) ==2){
                    if (key.compareTo(tree.right.key) > 0) {
                        // 右右
                        tree =  rightRightRotation(tree);
                    }else {
                        tree =  rightLeftRotation(tree);
                    }
                }
            }else {
                System.out.println("添加失败,值已存在");
            }
        }
        tree.height = max(height(tree.left),height(tree.right))+1;
        return  tree;
    }

    /**
     * 删除节点
     */

    public void remove(T key){
        AVLTreeNode<T> z = search(key);
        if(z != null){
           mRoot = remove(mRoot,z);
        }

    }

    private AVLTreeNode<T> remove(AVLTreeNode<T> tree, AVLTreeNode<T> z) {
        if (tree == null || z == null) {
            return null;
        }
        int cmp = z.key.compareTo(tree.key);
        if (cmp < 0) {
            // 待删除节点在左子树上
            tree.left = remove(tree.left,z);
          // 删除节点后,若AVL树失去平衡,则进行相应的调节。
            if (height(tree.right) - height(tree.left) == 2) {
                AVLTreeNode<T> r =  tree.right;
                if (height(r.left) > height(r.right)) {
                    tree = rightLeftRotation(tree);
                } else {
                    tree = rightRightRotation(tree);
                }
            }
        }else if (cmp>0) {
            // 待删除节点在右子树上
            tree.right = remove(tree.right, z);
            // 删除节点后,若AVL树失去平衡,则进行相应的调节。
            if (height(tree.left) - height(tree.right) == 2) {
                AVLTreeNode<T> l =  tree.left;
                if (height(l.right) > height(l.left)) {
                    tree = leftRightRotation(tree);
                } else {
                    tree = leftLeftRotation(tree);
                }
            }
        }else {
            // 待删除节点就是当前节点
            // 1.tree的左右子树都非空
            if(tree.left !=null && tree.right != null){
                if(height(tree.left)>height(tree.right)){
                    /* tree的左子树比右子树高;
                     则(01)找出tree的左子树中的最大节点
                       (02)将该最大节点的值赋值给tree。
                       (03)删除该最大节点。
                     这类似于用"tree的左子树中最大节点"做"tree"的替身;
                     采用这种方式的好处是: 删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。*/
                    AVLTreeNode<T> max = maximum(tree.left);
                    tree.key=max.key;
                    tree.left=remove(tree.left, max);

                }else {
                    /*tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
                     则(01)找出tree的右子树中的最小节点
                       (02)将该最小节点的值赋值给tree。
                       (03)删除该最小节点。
                     这类似于用"tree的右子树中最小节点"做"tree"的替身;
                     采用这种方式的好处是: 删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。*/
                    AVLTreeNode<T> min = minimum(tree.right);
                    tree.key=min.key;
                    tree.right=remove(tree.right,min);

                }
            }else {
                // 2有一个子树是空的,直接用子树替代
                AVLTreeNode<T> tmp = tree;
                tree = (tree.left!=null) ? tree.left : tree.right;
                tmp = null;
            }

        }

        return tree;
    }
    /**
     * 获取最大的节点
     */
    public T maximum(){
        AVLTreeNode<T> maximum = maximum(mRoot);
        if (maximum != null) {
            return maximum.key;
        }else {
            return null;
        }

    }

    private AVLTreeNode<T> maximum(AVLTreeNode<T> tree) {
        if (tree.right != null) {
            //最大节点在右子树
            return maximum(tree.right);
        }else {
            return tree;
        }
    }

    /**
     * 获取最小的节点
     */
    public T minimum(){
        AVLTreeNode<T> minimum = minimum(mRoot);
        if (minimum != null) {
            return minimum.key;
        }else {
            return null;
        }
    }

    private AVLTreeNode<T> minimum(AVLTreeNode<T> tree) {
        if (tree.left != null) {
            //最大节点在右子树
            return maximum(tree.left);
        }else {
            return tree;
        }
    }


    /**
     * 查找节点
     * @param key
     * @return
     */
    public AVLTreeNode<T> search(T key) {
        return search(mRoot,key);
    }

    private AVLTreeNode<T> search(AVLTreeNode<T> tree, T key) {
        if (tree == null) {
            return null;
        }else {
            if (key.compareTo(tree.key)>0) {
                return  search(tree.right,key);
            }else if (key.compareTo(tree.key)<0) {
                return search(tree.left,key);
            }else {
                return tree;
            }
        }
    }

    /**
     * 打印
     * @param tree      树
     * @param key       关键
     * @param direction 0- 跟节点  1 右子树  -1 左子树
     */
    private void print(AVLTreeNode<T> tree, T key, int direction) {

        if(tree != null) {
            // tree是根节点
            if(direction==0)
            {
                System.out.printf("%2d is root\n", tree.key);
            } else                // tree是分支节点
            {
                System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");
            }

            print(tree.left, tree.key, -1);
            print(tree.right,tree.key,  1);
        }
    }

    /**
     * 打印
     */
    public void print() {
        if (mRoot != null) {
            print(mRoot, mRoot.key, 0);
        }
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值