首页 > 编程语言 >平衡二叉树 -java实现

平衡二叉树 -java实现

时间:2022-09-23 10:01:07浏览次数:54  
标签:node java TreeNode height leftChild 二叉树 newNode 平衡 data

 

package tree;
/**
 * @author: tianhaichao
 * @date: 2022/9/22 15:38
 * @description:平衡二叉树AVL
 * 1、每个节点的左右子树的高度差不大于1 ---> |left.height-right.height|<=1
 * 2、每个节点的左右子树也是平衡二叉树
 */
public class AVLTree {
    static TreeNode root;
    public static void main(String[] args) {
        int[] array = new int[]{10, 3, 5, 2, 5, 6, 4, 12, 15, 16, 17, 18};
        for (int i : array) {
            AVLTree.insert(root, i);
            preTraversal(root);
            System.out.println("----" + i);
        }
        System.out.println("==========================");
        //排序输出
        midTraversal(root);
    }

    public static class TreeNode {
        // 该节点为顶点的子树深度
        int height;
        int data;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;

        public TreeNode(int data) {
            this.data = data;
        }
    }

    /**
     * @author: tianhaichao
     * @date: 2022/9/23 09:55
     * @description:实现算法使用到了递归
     * 用来实现每次变化后,校验、调整树使其达到平衡
     */
    public static void insert(TreeNode node, int data) {
        if (root == null) {
            root = new TreeNode(data);
            root.height = 1;
            return;
        }
        if (data >= node.data) {
            if (node.rightChild == null) {
                //新增叶子结点,没有子树,所以树深为1
                TreeNode newNode = new TreeNode(data);
                newNode.height = 1;
                newNode.parent = node;
                node.rightChild = newNode;
            } else {
                // 递归执行每一层
                insert(node.rightChild, data);
            }
        } else {
            if (node.leftChild == null) {
                TreeNode newNode = new TreeNode(data);
                newNode.height = 1;
                newNode.parent = node;
                node.leftChild = newNode;
            } else {
                insert(node.leftChild, data);
            }
        }
        /**
         递归  --插入返回后,每一层都执行下面代码校验当前节点是否满足平衡标准,并调整
         */
        // 更新子树深度
        node.height = calculateSonTreeDeep(node);
        // 计算平衡因子,执行调整 左子树大
        if (calculateBF(node) >= 2) {
            // 判断是否为LR
            if (calculateBF(node.leftChild) == 1) {
                // LR 先执行左旋转成LL
                leftRotate(node.leftChild);
            }
            // LL 执行右旋
            rightRotate(node);
        }
        // 计算平衡因子,执行调整 右子树大
        if (calculateBF(node) <= -2) {
            // 判断类型,执行调整
            if (calculateBF(node.rightChild) == 1) {
                // LR 先执行左旋转成LL
                rightRotate(node.rightChild);
            }
            // LL 执行右旋
            leftRotate(node);
        }
    }

    /**
     * @author: tianhaichao
     * @date: 2022/8/30 14:44
     * @description: node 旋转节点 RR 、LR执行左旋
     * 1、将右节点上提成为父节点
     * 2、父节点转为右节点的左孩子
     * 3、父节点的右孩子【替换成】右节点的左孩子,父节点的左孩子不变
     * return 旋转完后的父节点,也就是右孩子【将右节点上提成为父节点】
     */
    public static TreeNode leftRotate(TreeNode node) {
        TreeNode right = node.rightChild;
        TreeNode father = node;
        // 如果右节点存在左孩子,父节点的右孩子【替换成】右节点的左孩子
        father.rightChild = right.leftChild;
        // 将右节点上提成为父节点 变成祖父的孩子
        if (father.parent == null || father == root) {
            root = right;
        } else if (father.parent.leftChild == father) {
            father.parent.leftChild = right;
        } else {
            // 如果旋转节点是父节点的右节点
            father.parent.rightChild = right;
        }
        right.parent = father.parent;
//        父节点转为右节点的左孩子
        right.leftChild = father;
        father.parent = right;
        // 调整节点子树高度
        father.height = calculateSonTreeDeep(father);
        right.height = calculateSonTreeDeep(right);
        if (father.parent != null) {
            father.parent.height = calculateSonTreeDeep(father.parent);
        }
        return right;
    }

    /**
     * @return 旋转之后的父节点,也就是左孩子【将左节点上提成为父节点】
     * @author: tianhaichao
     * @date: 2022/9/20 18:31
     * @description: LL或RL执行右旋
     * 执行右旋,
     * 1、将左节点上提成为父节点
     * 2、父节点转为左节点的右孩子
     * 3、父节点的左孩子【替换成】左节点的右孩子,父节点的右孩子不变
     */
    public static TreeNode rightRotate(TreeNode node) {
        TreeNode left = node.leftChild;
        TreeNode father = node;
        // 父节点的左孩子【替换成】左节点的右孩子,父节点的右孩子不变
        father.leftChild = left.rightChild;
        //将左节点上提成为父节点
        if (father.parent == null || father == root) {
            root = left;
        } else if (father.parent.rightChild == father) {

            father.parent.rightChild = left;
        } else {
            father.parent.leftChild = left;
        }
        left.parent = father.parent;
        // 父节点转为左节点的右孩子
        father.parent = left;
        left.rightChild = father;
        // 调整节点子树高度
        father.height = calculateSonTreeDeep(father);
        left.height = calculateSonTreeDeep(left);
        if (father.parent != null) {
            father.parent.height = calculateSonTreeDeep(father.parent);
        }
        return left;
    }

    /**
     * @author: tianhaichao
     * @date: 2022/9/22 16:34
     * @description: 计算平衡因子
     */
    public static int calculateBF(TreeNode node) {
        if (node == null) {
            return 0;
        } else if (node.rightChild == null && node.leftChild == null) {
            return 0;
        } else if (node.leftChild == null) {
            return -node.rightChild.height;
        } else if (node.rightChild == null) {
            return node.leftChild.height;
        } else {
            return node.leftChild.height - node.rightChild.height;
        }
    }

    /**
     * @author: tianhaichao
     * @date: 2022/9/22 16:34
     * @description: 计算子树深度,TreeNode的height值
     */
    public static int calculateSonTreeDeep(TreeNode node) {
        if (node == null) {
            return 0;
        } else if (node.rightChild == null && node.leftChild == null) {
            return 1;
        } else if (node.leftChild == null) {
            return node.rightChild.height + 1;
        } else if (node.rightChild == null) {
            return node.leftChild.height + 1;
        } else {
            return Math.max(node.leftChild.height, node.rightChild.height) + 1;
        }
    }

    /**
     * @author: tianhaichao
     * @date: 2022/9/20 15:10
     * @description:中序遍历
     */
    public static void midTraversal(TreeNode node) {
        if (node == null) {
            return;
        }
        midTraversal(node.leftChild);
        System.out.print(node.data + "  ");
        midTraversal(node.rightChild);
    }

    /**
     * @author: tianhaichao
     * @date: 2022/9/20 15:10
     * @description:中序遍历
     */
    public static void preTraversal(TreeNode node) {
        if (node == null) {
            return;
        }
        int left = node.leftChild != null ? node.leftChild.data : 0;
        int right = node.rightChild != null ? node.rightChild.data : 0;
        System.out.print(node.data + "【" + node.height + "  " + left + "  " + right + "】" + "  ");
        preTraversal(node.leftChild);
        preTraversal(node.rightChild);
    }

}

  

 

标签:node,java,TreeNode,height,leftChild,二叉树,newNode,平衡,data
From: https://www.cnblogs.com/tianhaichao/p/16721680.html

相关文章

  • 正则,java匹配
    1.判断字符串中是否全为英文`booleanresult=str.matches("[a-zA-Z]+");//true:全文英文str.matches("[a-zA-Z0-9]+")//判断英文和数字`````2.提取字符串中所......
  • Mac下的Java运行时报错
    运行时报错Error:AJNIerrorhasoccurred,pleasecheckyourinstallationandtryagain为什么会出现这个问题?因为你的java和javac版本不一致为什么......
  • Java运行时错误: Prohibited package name: java.xx
    Java代码运行时如果出现如下错误,表示包名不能这样写,最好不要以“java”开头Exceptioninthread"main"java.lang.SecurityException:Prohibitedpackagename:java.da......
  • JAVA 绑定线程到指定CPU上
    CPU个数、核数、线程数、JAVA多线程关系cpu个数、核数、线程数的关系cpu个数:是指物理上,也及硬件上的核心数;核数:是逻辑上的,简单理解为逻辑上模拟出的核心数;线程数:是同一......
  • 指定一个目录下所有的java文件,把里面的内容格式化输出在md文件
    #指定一个目录下所有的java文件,把里面的内容格式化输出在md文件```java importjava.io.*;/***@authorMxhlin*@[email protected]*@Date2022/09/22/17:0......
  • Javaweb前基
    Javaweb01web静态web:htmlcss提供给所有人看的数据始终不会发生变化动态web:每个人不同时间不同地点看到的信息各不相同​技术栈:servlet/JSP、......
  • 对于Java中权限修饰符的理解
    老是把Java中权限修饰符给忘记,写一个博客加深印象吧权限分为四个作用域:当前类,同一个包,其他包的子类,其他包的类。首先要知道包的概念,Java中一个包是指一个package下的所......
  • JAVA 面向对象-中
    Java面向对象-中面向对象的特征二、继承性1.为什么要有类的继承性?(继承性的好处)①减少代码的冗余,提高了代码的复用性②便于功能的扩展③为之后多态性的使用,提供了前提......
  • Java序列化为什么必须实现 Serializable 接口???
    最近公司的在做服务化,需要把所有model包里的类都实现Serializable接口,同时还要显示指定serialVersionUID的值.听到这个需求,我脑海里就突然出现了好几个问题,比如说......
  • java String
    一、修改字符串的内容1、每个String类型的字符串都是只读的,所以需要修改字符串中的某些字符则比较困难。比如要在Strings="123";要在2之后插入一个字符串"45"那么需......