平衡二叉树 - 双旋转(左右旋转)

331 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

平衡二叉树 - 双旋转(左右旋转)

进行单旋转(即一次旋转)就可以将非平衡二叉树转成平衡二叉树, 但是在某些情况下,单旋转不能完成平衡二

叉树的转换

image-20220918162829954

双旋转原因分析

  1. 符合右旋转的条件
  2. 它的左子树的右子树的高度大于它的左子树的高度
  3. 对当前这个结点的左节点进行左旋转
  4. 再对当前结点进行右旋转

image-20220918214116829

package com.avl;
​
/**
 * @author Kcs 2022/9/18
 */
public class AvlTreeDemo {
    public static void main(String[] args) {
        //左旋转数组
        int[] arrLeft = {4, 3, 6, 5, 7, 8};
        //右旋转数组
        int[] arrRight = {10,12, 8, 9, 7, 6};
        //双旋转数组
        int[] arrDouble = {10,11, 7, 6, 8, 9};
​
​
        AvlTree avlTree = new AvlTree();
​
        for (int i = 0; i < arrDouble.length; i++) {
            avlTree.add(new Node(arrDouble[i]));
        }
        avlTree.infixOrder();
​
        System.out.println("平衡处理后~~~");
        System.out.println("当前根节点树的高度=" + avlTree.getRoot().height());
        System.out.println("树的左子树的高度=" + avlTree.getRoot().leftHeight());
        System.out.println("树的右子树的高度=" + avlTree.getRoot().rightHeight());
        System.out.println("当前根节点= "+avlTree.getRoot());
        System.out.println("当前根节点的左子节点= "+avlTree.getRoot().left);
        System.out.println("当前根节点的右子节点= "+avlTree.getRoot().right);
    }
}
​
/**
 * AVL树
 */
class AvlTree {
    private Node root;
​
    public Node getRoot() {
        return root;
    }
​
    /**
     * 添加结点
     * @param node 结点
     */
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }
​
    /**
     * 中序遍历
     */
    public void infixOrder() {
        if (root != null) {
            root.infixOrder();
        } else {
            System.out.println("二叉排序树为空!!");
        }
    }
​
}
​
/**
 * 结点
 */
class Node {
    /**
     * 值
     */
    int value;
    /**
     * 左右结点
     */
    Node left;
    Node right;
​
    public Node(int value) {
        this.value = value;
    }
​
    @Override
    public String toString() {
        return "Node{" + "value=" + value + '}';
    }
​
    /**
     * 返回当前节点的高度,以该节点为根节点的树的高度
     * @return 节点的高度
     */
    public int height() {
        return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
    }
​
    /**
     * 返回左子树的高度
     * @return 左子树高度
     */
    public int leftHeight() {
        if (left == null) {
            return 0;
        }
        return left.height();
    }
​
    /**
     * 返回右子树的高度
     * @return 右子树高度
     */
    public int rightHeight() {
        if (right == null) {
            return 0;
        }
        return right.height();
    }
​
    /**
     * 左旋转
     */
    private void leftRotate() {
        //1.创建一个新结点newNode,值为当前根节点值
        Node newNode = new Node(value);
        //2.将新节点的左子树设置为当前节点的左子树
        newNode.left = left;
        //3.将新节点的右子树设置为当前节点的右子树的左子树
        newNode.right = right.left;
        //4.将当前节点的值换为右子节点的值
        value = right.value;
        //5.将当前节点的右子树设置为右子树的右子树
        right = right.right;
        //6.将当前节点的左子树设置为新节点
        left = newNode;
    }
​
    /**
     * 右旋转
     */
    private void rightRotate() {
        // 1. 创建一个新结点newNode,值为当前根节点值
        Node newNode = new Node(value);
        // 2. 将新节点的右子树设置为当前节点的右子树
        newNode.right = right;
        // 3. 将新节点的左子树设置为当前节点的左子树的右子树
        newNode.left = left.right;
        // 4. 将当前节点的值为右子节点的值
        value = left.value;
        // 5. 将当前节点的左子树设置为左子树的左子树
        left = left.left;
        // 6. 将当前节点的右子树设置为新节点
        right = newNode;
    }
​
    /**
     * 添加结点
     * 递归添加结点,满足二叉排序树
     * @param node 结点信息
     */
    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);
            }
        }
​
        //右子树的高度 - 左子树的高度 > 1,则进行左旋转
        if (rightHeight() - leftHeight() > 1) {
            //它的右子树的 左子树的高度 大于 它的右子树的 右子树的高度
            if (right != null && right.leftHeight() > right.rightHeight()) {
                //先右子树右旋转
                right.rightRotate();
                //再对当前结点进行左旋转
                leftRotate();
            }else {
                //不满足,直接进行左旋转
                leftRotate();
            }
            return;
        }
​
        //左子树的高度 - 右子树的高度 > 1,则进行右旋转
        if (leftHeight() - rightHeight() > 1) {
            //它的左子树的右子树的高度大于它的左子树的高度
            if (left != null && left.rightHeight() > left.leftHeight()) {
                //当前结点的左子树,进行左旋转
                left.leftRotate();
                //当前结点进行右旋转
                rightRotate();
            }else {
                //直接进行右旋转
                rightRotate();
            }
        }
    }
​
    /**
     * 中序遍历
     */
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
​
}