• 数据结构-平衡二叉树


    平衡二叉树的重点在于对不平衡的进行旋转从而使它达到平衡.

    下面是我理解的平衡二叉树的操作总结:

    平衡因子(BF):
     这是一个描述平衡度的一个量,计算的方式为 左子树的深度-右子树的深度。

    我们可以从BF中就能知道左子树和右子树之间的平衡程度。

    插入数据

    平衡二叉树最复杂的就是将数据插入到树中了,因为要涉及到位置的调整。对于位置的调整在平衡二叉树中成为树的旋转.根据平衡因子的状态分为左旋和右旋.

    那什么时候需要进行旋转呢?

    这个问题确实值得思考,一般都是在平衡因子的绝对值大于1的时候就需要进行旋转了,也就是说左右子树的深度相差超过了1.

    那从什么地方做为跟节点进行旋转呢?

    这里有一个术语叫做最小不平衡子树,就是平衡因子绝对值大于1,并且最接近叶子节点的。

    我们旋转的时候,只需要对最小不平衡子树进行旋转就可以了。

    左旋:

    当平衡因子为正数的时候并且大于1的时候,进行左旋,左旋的方式为:
    根节点的左子树的右子树作为根节点的右子树,根节点作为左子树的右子树。

     右旋:

    当平衡因子为负数的时候,并且小于-1的时候进行右旋,右旋的方式为:
    将根节点的右节点的左子树作为根节点的右子树.
    根节点作为跟节点的右节点的左子树。

     

    注意: 

    上面两种实例根节点和子节点都是同一符号的,所以简单的进行左旋或者右旋就可以了。如下图:

    ,但是如果我们遇到符号不相同的情况下,需要进行两次旋转,如下图:

    这种情况下,第一次旋转是将C作为根节点右旋,之后再进行左旋.

    我们只需要记住正数的时候进行右旋,负数的时候进行左旋即可。

     上面的原理讲完了,下面是具体的JAVA代码实现:

    package com.hotusm.datastructure.tree;
    
    /**
     * @author luqibao
     * @date 2017/3/31
     */
    public class AVLTree {
    
    
        /**
         * 平衡因子所属的状态
         */
        private static final int LH = 1;   //左边高
        private static final int EH = 0;   //一样高
        private static final int RH = -1;  //右边高
    
    
        private TreeNode root;  //树的根
    
    
        /**
         * 向平衡二叉树插入节点
         *
         * @param data
         */
        public void insertNode(int data) {
    
            if (this.root == null) {
                this.root = new TreeNode(null, null, EH, data, null);
                return;
            }
            insertAVLNode(this.root, data);
    
        }
    
    
        /**
         * 进行右旋
         *
         * @param treeNode 需要旋转的根
         */
        /*
         * 右旋
         * 将根的左子树的右子树作为根的左子树
         * 左子树的右子树指向根(最后左子树变为了根,根变为了右子树)
         */
        private void rRotate(TreeNode treeNode) {
            TreeNode root = treeNode.getLeft();
            if (treeNode == this.root) {
                this.root = root;
            }
            treeNode.setLeft(root.getRight());
            root.setRight(treeNode);
        }
    
        /**
         * 进行左旋
         *
         * @param treeNode 需要旋转的根
         */
        /*
        * 左旋
        * 将根的右子树的左子树作为根的右子树
        * 右子树的左子树指向根(最后右子树变为个根,根变为了左子树)
        * */
        private void lRotate(TreeNode treeNode) {
            TreeNode root = treeNode.getRight();
            if (treeNode == this.root) {
                this.root = root;
            }
            treeNode.setRight(root.getLeft());
            root.setLeft(treeNode);
        }
    
        /**
         * 左平衡旋转(左边平衡因子太大的原因  需要向右移动)
         *
         * @param root
         */
        private void leftBalance(TreeNode root) {
            TreeNode leftNode = root.getLeft();
            switch (leftNode.getBf()) {
                case LH:
                    root.setBf(EH);
                    leftNode.setBf(EH);
                    rRotate(root);
                    break;
                //如果是这种情况  根和左子树平衡因子不是同符号的  所以需要两次的旋转
                case RH:
                    TreeNode doubleLeftNode = leftNode.getRight();// 左子树的右子树
                    switch (doubleLeftNode.getBf()) {
                        case RH:
                            root.setBf(EH);
                            leftNode.setBf(LH);
                            break;
                        case EH:
                            root.setBf(EH);
                            leftNode.setBf(EH);
                            break;
                        case LH:
                            root.setBf(RH);
                            leftNode.setBf(EH);
                            break;
                    }
                    doubleLeftNode.setBf(EH);
                    lRotate(leftNode);
                    rRotate(root);
                    break;
            }
        }
    
        /**
         * 右平衡旋转 右边平衡因子太大的原因
         *
         * @param root
         */
        private void rightBalance(TreeNode root) {
    
            TreeNode rightNode = root.getRight();
    
            switch (rightNode.getBf()) {
                case RH:
                    root.setBf(EH);
                    rightNode.setBf(EH);
                    lRotate(root);
                    break;
                case LH: //如果是这种情况 那么根和右子树的平衡因子不同符号 所以需要进行两次的旋转
                    TreeNode doubleLeftNode = rightNode.getLeft();
                    switch (doubleLeftNode.getBf()) {
                        case LH:
                            root.setBf(EH);
                            rightNode.setBf(RH);
                            break;
                        case EH:
                            root.setBf(EH);
                            rightNode.setBf(EH);
                            break;
                        case RH:
                            root.setBf(LH);
                            rightNode.setBf(EH);
                            break;
                    }
                    doubleLeftNode.setBf(EH);
                    rRotate(rightNode);
                    lRotate(root);
                    break;
            }
    
        }
    
        /**
         * 向平衡二叉树插入数据data
         * 如果增高那么返回true  否则返回false
         *
         * @param data
         * @return
         */
        private boolean insertAVLNode(TreeNode root, int data) {
            boolean taller = false;
            if (root.getData() == data) {
                return false;
            }
            if (data < root.getData()) {
                if (root.getLeft()==null){
                    TreeNode child=new TreeNode(null,null,EH,data,root);
                    root.setLeft(child);
                    if (root.getBf()==EH){
                        root.setBf(LH);
                        return true;
                    }
                    /*
                     * 在child 节点未插入到root的左子树中的时候
                     * root的BF只能有两种情况 EH(左右都没节点) 和 RH(有右叶子节点)
                     * 所以还有一种可能就是当时RH的时候 BF变为EH
                     * */
                    root.setBf(EH);
                }else {
                    taller=insertAVLNode(root.getLeft(),data);
                    if (taller){
                        switch (root.getBf()){
                            case LH:
                                leftBalance(root);
                                taller=false;
                                break;
                            case EH:
                                /*
                                 *进行上一级的回溯
                                 *      O
                                 *    O   O
                                 *  O  O
                                 */
                                root.setBf(LH);
                                taller=true;
                                break;
                            default:
                                root.setBf(EH);
                                taller=false;
                        }
                    }
                }
            } else {
                if (root.getRight()==null){
                    TreeNode child=new TreeNode(null,null,EH,data,root);
                    root.setRight(child);
                    if (root.getBf()==EH){
                        root.setBf(RH);
                    }
                    /*
                    * 和上面的类似,在右子树插入到root之前 root的BF只有两种情况 EH(没有左右节点) LH (只有左叶子节点)
                    * */
                    root.setBf(EH);
                }else {
                    taller=insertAVLNode(root.getRight(),data);
                    if (taller){
                        switch (root.getBf()){
                            case RH:
                                rightBalance(root);
                                taller=false;
                                break;
                            case LH:
                                root.setBf(EH);
                                taller=false;
                                break;
                            default:
                            /*
                             *这里会进行回溯到更上的一级进行判断 从而进行旋转
                             *              O
                             *            O   O
                             *               O  O
                             */
                                root.setBf(RH);
                                taller=true;
                        }
                    }
                }
            }
            return taller;
        }
    
        public static void main(String[] args) {
            testInsertAVLTree();
        }
    
        public static void testInsertAVLTree() {
            AVLTree avlTree = new AVLTree();
            avlTree.insertNode(1);
            avlTree.insertNode(2);
            avlTree.insertNode(3);
            avlTree.insertNode(4);
            avlTree.insertNode(5);
    
        }
    
        /**
         * 树的节点
         */
        public static class TreeNode {
    
            private TreeNode left;
            private TreeNode right;
            private TreeNode parent;
            private int bf; //平衡因子
            private int data;
    
            public TreeNode(TreeNode left, TreeNode right, int bf, int data, TreeNode parent) {
                this.left = left;
                this.right = right;
                this.bf = bf;
                this.data = data;
                this.parent = parent;
            }
    
            public TreeNode getLeft() {
                return left;
            }
    
            public void setLeft(TreeNode left) {
                this.left = left;
            }
    
            public TreeNode getRight() {
                return right;
            }
    
            public void setRight(TreeNode right) {
                this.right = right;
            }
    
            public int getBf() {
                return bf;
            }
    
            public void setBf(int bf) {
                this.bf = bf;
            }
    
            public int getData() {
                return data;
            }
    
            public TreeNode getParent() {
                return parent;
            }
    
            public void setParent(TreeNode parent) {
                this.parent = parent;
            }
    
            public void setData(int data) {
                this.data = data;
            }
    
            @Override
            public String toString() {
                return "TreeNode{" +
                        "left=" + left +
                        ", right=" + right +
                        ", bf=" + bf +
                        ", data=" + data +
                        '}';
            }
        }
    }

    代码中进行了详细的注释,看起来应该是没问题的。

    参考:大话数据结构 第八章

  • 相关阅读:
    安装VMware16兼容Hyper-v+WSL2+Docker+解决0x80370102报错
    家用联通光纤开启IPv6
    配置微软Azure大数据HDInsight云集群
    Hadoop集群搭建-05安装配置YARN
    Hadoop集群搭建-04安装配置HDFS
    Hadoop集群搭建-03编译安装hadoop
    Hadoop集群搭建-02安装配置Zookeeper
    Hadoop集群搭建-01前期准备
    springMVC+request.session实现用户登录和访问权限控制
    idea+spring4+springmvc+mybatis+maven实现简单增删改查CRUD
  • 原文地址:https://www.cnblogs.com/zr520/p/6657074.html
Copyright © 2020-2023  润新知