AVL self-balancing tree

Because the AVL self-balancing tree is based on the binary sort tree, I will briefly describe the binary sort tree and code implementation.

Binary Sort (Search) Tree (BST)

Binary Sort Tree: BST: (Binary Sort(Search) Tree), for any non-leaf node of the binary sort tree, the value of the left child node is required to be smaller than the value of the current node, and the value of the right child node is smaller than the value of the current node Great value. Special note: If there are the same values, the node can be placed in the left child node or the right child node

For example, for the previous data (7, 3, 10, 12, 5, 1, 9), the corresponding binary sort tree is:

Because the insertion of the binary sort tree is relatively simple, the following code is directly implemented

First create a node class (because the self-balancing will also use this node, just add a new method to the node, I won’t go into details later)

class Node{
    public int val;
    public Node left;
    public Node right;

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

    public void add(Node node){
        if(node == null)
            return;
        if(node.val < this.val){
            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);
            }
        }
    }

    public void infixOrder(){
        if(this.left != null){
            this.left.infixOrder();
        }
        System.out.println(this);
        if(this.right != null){
            this.right.infixOrder();
        }
    }

    @Override
    public String toString() {
        return "Node{" +
                "val=" + val +
                '}';
    }
}

Create a binary search tree

class BinarySortTree{
    private Node root;

    public void setRoot(Node root) {
        this.root = root;
    }

    public void add(Node node){
        if(root == null){
            root = node;
            return;
        }
        root.add(node);
    }

    public void infixOrder(){
        if(root != null){
            root.infixOrder();
            return;
        }
        System.out.println("二叉排序树为空~~~");
    }
    
}

The binary search tree and node class have been created. If you need to add nodes, you need to traverse the array to add nodes

    BinarySortTree binarySortTree = new BinarySortTree();
    int[] arr = {7, 3, 10, 12, 5, 1, 9};
    for (int i = 0; i < arr.length; i++) {
    binarySortTree.add(new Node(arr[i]));

The following implements the delete node function of the binary sort tree

Because deleting a node needs to get this node and the parent node of this and node, add search() and searchParent() methods to the node class and encapsulate it in the tree class

public Node search(int val){
    if(this.val == val){
        return this;
    }
    if(val < this.val){
        if (this.left != null){
            return this.left.search(val);
        }else
            return null;
    }else {
        if (this.right != null){
            return this.right.search(val);
        }else
            return null;
    }
}
public Node search(int val){
    if(root != null){
        return root.search(val);
    }
    return null;
}
public Node searchParent(int val){
    if(this.left != null && this.left.val == val ||
            this.right != null && this.right.val == val){
        return this;
    }
    if(val < this.val && this.left != null){
        return this.left.searchParent(val);
    }else if(val > this.val && this.right != null){
        return this.right.searchParent(val);
    }
    return null;
}
public Node searchParent(int val){
    if(root != null){
        return root.searchParent(val);
    }
    return null;
}

The deletion of a binary sort tree is more complicated, and there are three situations to consider

1. Delete leaf nodes (for example: 2, 5, 9, 12)

 

if(target.left == null && target.right == null){//叶子节点
    if (parent.left != null && parent.left.val == val){
        parent.left = null;
        return;
    }
    if(parent.right != null && parent.right.val == val){
        parent.right = null;
        return;
    }

2. Delete nodes with only one subtree (for example: 1)

else {//有一个子树的叶子节点
   if(parent.left.val == val){
       if(target.left != null){
           parent.left = target.left;
           return;
       }
       if(target.right != null){
           parent.left = target.right;
           return;
       }
   }else {
       if(target.left != null){
           parent.right = target.left;
           return;
       }
       if(target.right != null){
           parent.right= target.right;
           return;
       }
   }

3. Delete nodes with two subtrees. (For example: 7, 3, 10)

There are two ways here, either to delete the minimum value of the right subtree, or to delete the maximum value of the left subtree. I implement both methods. In practice, I only need to call one.

public int delLeftMax(Node node){
    Node target = node;
    while (target.right != null){
        target = target.right;
    }
    delNode(target.val);
    return target.val;
}
public int delRightTreeMin(Node node){
    Node target = node;
    while(target.left != null){
        target = target.left;
    }
    delNode(target.val);
    return target.val;
}
else if(target.left != null && target.right != null){//两颗子树的非叶子节点
   int minVal = delRightTreeMin(target.right);
   target.val = minVal;

Delete node code summary

public void delNode(int val){
    if (root == null){
        return;
    }
    if (root.val == val && root.left == null && root.right == null){
        root = null;
        return;
    }
    Node target = search(val);
    if (target == null)
        return;
    Node parent = searchParent(val);
    if (target.left == null && target.right == null){
        if (parent.left != null && parent.left.val == val){
            parent.left = null;
            return;
        }else{
            parent.right = null;
            return;
        }
    }else if (target.left != null && target.right != null){
        int maxVal = delLeftMax(target.left);
        target.val = maxVal;
    }else {
        if (parent.left != null && parent.left.val == val){
            if (target.left != null){
                parent.left = target.left;
                return;
            }else {
                parent.left = target.right;
                return;
            }
        }else {
            if (target.left != null){
                parent.right = target.left;
                return;
            }else {
                parent.right = target.right;
                return;
            }
        }
    }
}

The above is the realization process of the binary sort tree. Analyze possible problems with binary sorting

Give you a sequence {1,2,3,4,5,6}, ask to create a binary sort tree (BST), and analyze the problem.

Analysis of the problems with BST on the left:

1. The left subtree is all empty, which looks more like a singly linked list in terms of form.

2. Insertion speed has no effect

3. The query speed is significantly reduced (because it needs to be compared in order), and the advantages of BST cannot be used, because the left subtree needs to be compared each time, and the query speed is slower than that of a singly linked list

4. Solution-Balanced Binary Tree (AVL) 

Balanced binary tree

Balanced binary search tree is also called self-balancing binary search tree (Self-balancing binary search tree) is also called AVL tree, which can ensure high query efficiency.

It has the following characteristics: it is an empty tree or the absolute value of the height difference between its left and right subtrees does not exceed 1, and the left and right subtrees are both a balanced binary tree. The commonly used implementation methods of balanced binary tree include red-black tree, AVL, scapegoat tree, Treap, stretch tree, etc.

Because the depth of the tree needs to be discussed here, three methods are added to the node class, height(), leftHeight(), rightHeight()

public int leftHeight(){
    if (left != null){
        return left.height();
    }
    return 0;
}
public int rightHeight(){
    if (right != null){
        return right.height();
    }
    return 0;
}
public int height(){
    return Math.max(left == null ? 0 : left.height(),
            right == null ? 0 : right.height()) + 1;
}

AVL tree rotate left

Problem: rightHeight()-leftHeight()> 1 is established when 8 is inserted. At this time, it is no longer an avl tree.

What to do-rotate left.

1. Create a new node newNode (created with a value of 4), create a new node, the value is equal to the value of the current root node

//Set the left subtree of the new node to the left subtree of the current node

2. newNode.left = left //Set the right subtree of the new node to the left subtree of the right subtree of the current node

3. newNode.right =right.left; Change the value of the current node to the value of the right child node

4、value=right.value;

//Set the right subtree of the current node to the right subtree of the right subtree

5.、right=right.right;

Set the left subtree of the current node as the new node

6、 left=newLeft;

Left rotation code implementation

public void leftRotate(){
    Node newNode = new Node(val);
    newNode.left = left;
    newNode.right = right.left;
    val = right.val;
    right = right.right;
    left = newNode;
}

AVL rotate right

Question: When inserting 6, leftHeight()-rightHeight()> 1 is established. At this time, it is no longer an avl tree.

How to deal with-right rotation. [It is to reduce the height of the left subtree], here is to rotate the node 9 to the right subtree through right rotation

1. Create a new node newNode (created with a value of 10), create a new node, the value is equal to the value of the current root node

//Set the right subtree of the new node to the right subtree of the current node

2、 newNode.right = right

//Set the left subtree of the new node to the right subtree of the left subtree of the current node

3、newNode.left =left.right;

Change the value of the current node to the value of the left child node

4、value=left.value;

//Set the left subtree of the current node to the left subtree of the left subtree

5、 left=left.left;

Set the right subtree of the current node as the new node

6、 right=newLeft;

Right rotation code implementation

public void rightRotate(){
    Node newNode = new Node(val);
    newNode.right = right;
    newNode.left = left.right;
    val = left.val;
    left = left.left;
    right = newNode;
}

Double rotation analysis

In the first two series, a single rotation (that is, one rotation) can convert an unbalanced binary tree into a balanced binary tree, but in some cases, a single rotation cannot complete the conversion of a balanced binary tree. For example, the sequence int[] arr = {10, 11, 7, 6, 8, 9 }; Run the original code to see that it has not been converted into an AVL tree. int[] arr = {2,1,6,5, 7,3}; // Run the original code to see that it has not been converted into an AVL tree

So here you should first rotate the left node of the root node to the left, and then to the right, to rewrite the add method

public void add(Node node){
    if (node.val < val){
        if (left != null){
            left.add(node);
        }else {
            left = node;
        }
    }else {
        if (right != null){
            right.add(node);
        }else {
            right = node;
        }
    }
    if((leftHeight() - rightHeight()) > 1){
        if (left != null && (left.rightHeight() - left.leftHeight()) > 1){
            left.leftRotate();
            rightRotate();
        }else {
            rightRotate();
            return;
        }
    }
    if ((rightHeight() - leftHeight()) > 1){
        if (right != null && (right.leftHeight() - right.rightHeight()) > 1){
            right.rightRotate();
            leftHeight();
        }else {
            leftRotate();
            return;
        }
    }

 

Guess you like

Origin blog.csdn.net/qq_45796208/article/details/111920129