平衡二分木—AVL木

コンピュータサイエンスでは、AVLツリーは発明された最初の自己平衡二分探索木です。AVLツリー内の任意のノードの2つのサブツリーの高さの最大差は1であるため、高さバランスツリーとも呼ばれます。追加と削除では、ツリーのバランスを取り直すために1つ以上のツリーローテーションが必要になる場合があります。

特徴

AVLツリーは本質的にバイナリ検索ツリーであり、次の特徴があります。

  • 二分探索木です
  • 各ノードの左右のサブツリーの高さの差の絶対値(バランス係数)は最大1です。

次の図はAVLツリーであり、各ノードはバランス係数でマークされてい

ます。ノード4の左側のサブツリーの高さは0であり、右側のサブツリーは存在しないため、バランス係数は0-(-1)=です。 1;すべての葉ノードには左右のサブツリーがないため、バランス係数は0です。

上記のAVLツリーの場合、0が挿入されると、この時点でのバイナリツリーは次のようになります。

ノード4のバランス係数は2であり、AVLツリーのバランスを崩します。では、AVLのバランスをどのように復元するのでしょうか。左回転と右回転の2回の操作で完了します。

スピン

AVL木の回転は、左右タイプ、左右タイプ、左右タイプ、左右タイプの4つのケースに分けられます。

左左

グラフ内のノードが左に偏っている状況では、左左型と呼ばれますが、このとき、ノード4で右回転操作を行い、バランスを取り戻します。

右回転:2つのノードを時計回りに回転して、親ノード4がそれ自体の左側の子ノード1に置き換えられ、ノード4がノード1の右側の子ノードになります。

例を示し

ます。ノード6のバランス係数は2で、この時点では左左タイプであり、右利きの操作が実行されます。このとき、ノード4の右の子がノード6の左の子になります。

右右タイプ


写真は左手操作用の右から右へのタイプを示しています

右左型


図は右左タイプです。まず、ノード6で右利きの操作を実行し、次にノード4で左利きの操作を実行します。

左右


図は左右のタイプを示しています。まず、ノード2で左側の操作を実行し、ノード8で右側の操作を実行します。

コード

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_46122005/article/details/111052377