Day584&585.平衡二叉树 -数据结构和算法Java

Posted 阿昌喜欢吃黄桃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day584&585.平衡二叉树 -数据结构和算法Java相关的知识,希望对你有一定的参考价值。

平衡二叉树

一、出现的原因

解决二叉排序树的问题


二、介绍


三、平衡思路

1、左旋转

  • 左旋转思路分析
    因为左子树高度为1,右子树高度为3,所以要将左侧进行调整,所以进行左旋转

  • 代码实现

package com.achang.avl;


/**
 * 平衡二叉树
 */
public class AVLTreeDemo 
    public static void main(String[] args) 
        int[] arr = 4,3,6,5,7,8;
        AVLTree avlTree = new AVLTree();
        for (int i : arr) 
            avlTree.add(new Node(i));
        

        System.out.println("中序遍历:");
        avlTree.midOrder();
        System.out.println("树的高度为【"+avlTree.getRoot().height()+"】");
        System.out.println("树的左子树高度为【"+avlTree.getRoot().leftHeight()+"】");
        System.out.println("树的右子树高度为【"+avlTree.getRoot().rightHeight()+"】");
    






//平衡二叉树
class AVLTree
    private Node root;

    public Node getRoot()
        return root;
    

    public void add(Node addNode) 
        if (root != null) 
            this.root.add(addNode);
         else 
            this.root = addNode;
        
    

    /**
     * @param node 传入Node节点,当做一颗二叉排序数的根节点
     * @return 以node为根节点的二叉排序树的最小节点的值,并同时删除这个最小节点
     */
    public int deleteRightTreeMin(Node node)
        Node temp = node;
        //循环的查找左节点,最会找到最小值
        while (temp.left != null)
            temp = temp.left;
        

        //这时temp就指向了最小节点
        deleteNodeByValue(temp.value);
        return temp.value;
    

    public void deleteNodeByValue(int value) 
        if (root == null) 
            return;
         else 
            Node targetNode = findNodeByValue(value);
            if (targetNode == null) //找不到要删除的节点
                return;
            
            if (root.left == null && root.right == null) //没有父节点,只有一个节点的情况或当前节点的left和right同时都等于null
                root = null;
                return;
            

            //找父节点
            Node parent = findParentNodeByValue(value);

            //第一种情况:叶子节点的情况
            if (targetNode.left == null && targetNode.right == null) 
                //判断targetNode是父节点的左子节点还是右子节点
                if (parent.left != null && parent.left.value == value) 
                    parent.left = null;
                 else if (parent.right != null && parent.right.value == value) 
                    parent.right = null;
                
                //第二种情况:含有左右子树的情况
             else if (targetNode.left != null && targetNode.right != null) 
                targetNode.value = deleteRightTreeMin(targetNode.right);
                //第三种情况:只有一颗子树的情况
             else 
                //如果targetNode有左子节点
                if (targetNode.left != null) 
                    if (parent != null)
                        //如果targetNode是parent的左子节点
                        if (value == parent.left.value) 
                            parent.left = targetNode.left;
                         else 
                            //targetNode是parent的右子节点
                            parent.right = targetNode.left;
                        
                    else 
                        root = targetNode.left;
                    
                 else 
                    if (parent != null)
                        //如果targetNode有右子节点
                        if (value == parent.left.value) 
                            //如果targetNode是parent的左子节点
                            parent.left = targetNode.right;
                         else 
                            //targetNode是parent的右子节点
                            parent.right = targetNode.right;
                        
                    else 
                        root = targetNode.right;
                    
                
            
        

    

    public void midOrder() 
        if (root != null) 
            this.root.midOrder();
         else 
            System.out.println("当前二叉排序树为空树,请添加节点");
        
    

    public Node findParentNodeByValue(int value) 
        if (root != null) 
            return root.findParentNodeByValue(value);
         else 
            return null;
        
    

    public Node findNodeByValue(int value) 
        if (root != null) 
            return root.findNodeByValue(value);
         else 
            return null;
        
    


//节点
class Node 
    int value;
    Node left;
    Node right;

    public Node(int vale) 
        this.value = vale;
    

    /**
     * 返回左子树的高度
     */
    public int leftHeight()
        return left == null ? 0 : left.height();
    

    /**
     * 返回右子树的高度
     */
    public int rightHeight()
        return right == null ? 0 : right.height();
    

    /**
     * 返回当前节点为根节点,树的高度
     */
    public int height()
        return Math.max(left == null ? 0 :left.height(),right == null ? 0 : right.height()) + 1;
    

    //查找要删除节点的父节点
    public Node findParentNodeByValue(int value) 
        if ((this.left != null && this.left.value == value)
                || (this.right != null && this.right.value == value)) 
            return this;
         else 
            if (this.left != null && value < this.value) 
                return this.left.findParentNodeByValue(value);
             else if (this.right != null && value >= this.value) 
                return this.right.findParentNodeByValue(value);
             else 
                //没有找到父节点
                return null;
            
        
    

    /**
     * 查找要删除的节点,如果找到返回Node,不然就返回null
     *
     * @param value 希望删除的节点的value值
     */
    public Node findNodeByValue(int value) 
        if (value == this.value) 
            return this;
         else if (value < this.value) 
            if (this.left != null) 
                return this.left.findNodeByValue(value);
             else 
                return null;
            
         else 
            if (this.right != null) 
                return this.right.findNodeByValue(value);
             else 
                return null;
            
        
    

    //添加节点
    public void add(Node node) 
        if (node == null) 
            return;
        

        if (node.value < this.value) 
            if (this.left == null) 
                this.left = node;
             else 
                this.left.add(node);
            
         else 
            if (this.right == null) 
                this.right = node;
             else 
                this.right.add(node);
            
        

        //当添加完一个节点后,需要去判断是否需要平衡,采用哪一种平衡方式
        //当前出现需要平衡的情况
        if (rightHeight() - leftHeight() > 1)
            //左旋转
            leftRotate();
        
    

    //中序遍历
    public void midOrder() 
        if (this.left != null) 
            this.left.midOrder();
        
        System.out.println(this);
        if (this.right != null) 
            this.right.midOrder();
        
    

    //平衡左旋转
    public void leftRotate()
        //创建一个新节点,值为当前根节点
        Node newRootNode = new Node(value);
        newRootNode.left = left;
        newRootNode.right = right.left;
        value = right.value;
        right = right.right;
        left = newRootNode;
    

    @Override
    public String toString() 
        return "Node【" + value + "】";
    



2、右旋转

  • 右旋转思路分析

  • 代码实现
package com.achang.avl;


/**
 * 平衡二叉树
 */
public class AVLTreeDemo 
    public static void main(String[] args) 
//        int[] arr = 4,3,6,5,7,8;
        int[] arr = 10,12,8,9,7,6;
        AVLTree avlTree = new AVLTree();
        for (int i : arr) 
            avlTree.add(new Node(i));
        

        System.out.println("中序遍历:");
        avlTree.midOrder();
        System.out.println("树的高度为【"+avlTree.getRoot().height()+"】");
        System.out.println("树的左子树高度为【"+avlTree.getRoot().leftHeight()+"】");
        System.out.println("树的右子树高度为【"+avlTree.getRoot().rightHeight()+"】");
    






//平衡二叉树
class AVLTree
    private Node root;

    public Node getRoot()
        return root;
    

    public void add(Node addNode) 
        if (root != null) 
            this.root.add(addNode);
         else 
            this.root = addNode;
        
    

    /**
     * @param node 传入Node节点,当做一颗二叉排序数的根节点
     * @return 以node为根节点的二叉排序树的最小节点的值,并同时删除这个最小节点
     */
    public int deleteRightTreeMin(Node node)
        Node temp = node;
        //循环的查找左节点,最会找到最小值
        while (temp.left != null)
            temp = temp.left;
        

        //这时temp就指向了最小节点
        deleteNodeByValue(temp.value);
        return temp.value;
    

    public void deleteNodeByValue(int value) 
        if (root == null) 
            return;
         else 
            Node targetNode = findNodeByValue(value);
            if (targetNode == null) //找不到要删除的节点
                return;
            
            if (root.left == null && root.right == null) //没有父节点,只有一个节点的情况或当前节点的left和right同时都等于null
                root = null;
                return;
            

            //找父节点
            Node parent = findParentNodeByValue(value);

            //第一种情况:叶子节点的情况
            if (targetNode.left == null && targetNode.right == null) 
                //判断targetNode是父节点的左子节点还是右子节点
                if (parent.left != null && parent.left.value == value) 
                    parent.left = null;
                 else if (parent.right != null && parent.right.value == value) 
                    parent.right = null;
                
                //第二种情况:含有左右子树的情况
             else if (targetNode.left != null && targetNode.right != null) 
                targetNode.value = deleteRightTreeMin(targetNode.right);
                //第三种情况:只有一颗子树的情况
             else 
                //如果targetNode有左子节点
                if (targetNode.left != null) 
                    if (parent != null)
                        //如果targetNode是parent的左子节点
                        if (value == parent.left.value) 
                            parent.left = targetNode.left;
                         else 
                            //targetNode是parent的右子节点
                            parent.right 平衡二叉树&B-树

判断平衡二叉树

经典算法二叉树 & 平衡二叉树 & 红黑树

每日一点平衡二叉树 & 二叉排序树

剑指offer平衡二叉树

平衡二叉树 & 红黑树 & 哈夫曼