AVI 自平衡二叉树

平衡二叉树

  • 本质是二叉查找树的一种

  • 每个节点的左右子树的高度差的绝对值(平衡因子)最多为1 ,| leftTreeHeightmax - rightTreeHeightmax| <= 1

  • avi树图 (当左子树或是右子树,为空,默认值是-1)

    pin
    当多个节点变多的时候

旋转

  • 当avi的平衡因子大于1的时候,就会打破avi的平衡,这时我们需要左旋转或右旋转,来重新让它平衡。

  • 对于AVI的旋转分为四种情况,分别是左左型,右右型,左右型,右左型

  • 左左型 — 像图中一样,所有节点都偏向左边的情况,这个时候我们需要右旋操作

    在这里插入图片描述
    右旋:即顺时针旋转两个节点,使父节点4被左节点1取代,而节点4成为节点1的右节点。(总结:平衡因子为2的节点,成为其左子树的右子树,原来左子树的右子树,成为其的左子树,平衡因子在从新更新
    在这里插入图片描述

  • 右右型 – 节点集中在右边,需要左旋操作(平衡因子为2的点,成为其右子树的左子树,原来右子树的左子树,变成其右子树

    在这里插入图片描述

  • 右左型 – 先选择右旋(将其变成右右型),在旋转左旋 (先将其变成右右型,在依照右右型来处理

    在这里插入图片描述

  • 左右型 — 先将其变成左左型

    在这里插入图片描述

public class Node {
    
    
    int data;
    Node lchild;
    Node rchild;
    int height;

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

public class AVLTree {
    
    
    private Node root;

    // 记录节点的高度
    private int height(Node node) {
    
    
        if (node == null) {
    
    
            return -1;
        } else {
    
    
            return node.height;
        }
    }

    // 右右型 左旋
    private Node L_Rotate(Node node) {
    
    
        Node temp;

        // 进行旋转
        temp = node.rchild;
        node.rchild = temp.lchild;
        temp.lchild = node;

        // 重新计算高度
        node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
        temp.height = Math.max(height(temp.lchild), height(temp.rchild)) + 1;

        return temp;
    }

    // 左左型 右旋
    private Node R_Rotate(Node node) {
    
    
        Node temp;

        // 进行旋转
        temp = node.lchild;
        node.lchild = temp.rchild;
        temp.rchild = node;

        // 重新计算高度
        node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
        temp.height = Math.max(height(temp.lchild), height(temp.rchild)) + 1;

        return temp;
    }

    // 左右型 先进行左旋在进行右旋
    private Node L_R_Rotate(Node node) {
    
    
        // 对左子节点进行左旋
        node.lchild = L_Rotate(node.lchild);

        // 对节点进行右旋
        return R_Rotate(node);
    }

    // 右左型 先进性右旋在进行左旋
    private Node R_L_Rotate(Node node) {
    
    
        // 对右子节点进行右旋
        node.rchild = R_Rotate(node.rchild);

        // 对节点进行左旋
        return L_Rotate(node);
    }

    public void insert(int data) {
    
    
        root = insert(data, root);
    }

    // 插入操作
    private Node insert(int data, Node node) {
    
    
        if (node == null) {
    
    
            node = new Node(data);
        } else if (data < node.data) {
    
    
            // 向左子节点递归插入
            node.lchild = insert(data, node.lchild);

            // 如果左子节点的高度比右子节点的高度大2 则进行旋转调整
            if (height(node.lchild) - height(node.rchild) == 2){
    
    
                if (data < node.lchild.data) {
    
      // 左左型
                    node = R_Rotate(node);
                } else {
    
       // 左右型
                    node = R_L_Rotate(node);
                }
            }
        } else if (data > node.data) {
    
    
            // 向右子节点递归插入
            node.rchild = insert(data, node.rchild);

            // 如果右子节点的高度比左子节点的高度大2 则进行旋转调整
            if (height(node.rchild) - height(node.lchild) == 2) {
    
    
                if (data > node.rchild.data) {
    
     // 右右型
                    node = L_Rotate(node);
                } else {
    
      // 右左型
                    node = R_L_Rotate(node);
                }
            }
        }
        // 如果 data = node.data 这个节点在树上存在 什么也不做

        node.height = Math.max(height(node.lchild), height(node.rchild)) + 1;
        return node;
    }

    // 中序遍历AVL树
    public void inOrder() {
    
    
        inOrder(root);
    }

    private void inOrder(Node node) {
    
    
        if (node != null) {
    
    
            inOrder(node.lchild);
            System.out.println(node.data);
            inOrder(node.rchild);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45788043/article/details/112600527