Practical application of tree structure 2

Binary sort tree

Requirements: for a sequence (7, 3, 10, 12, 5, 1, 9), it is required to query and add data efficiently

Basic introduction:
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 that of the current node, and the value of the right child node is required to be larger than that of the current node.

Special note: if you have the same value, you can put this node on 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:

Binary sort tree creation and traversal

An array is created into the corresponding binary sort tree, and the middle order is used to traverse the binary sort tree

package com.atguigu.binarysorttree;

/**
 * @ClassName BinarySortTreeDemo
 * @Author Jeri
 * @Date 2022-02-26 17:58
 * @Description Creation, traversal and deletion of binary sort tree
 */

//Create node class object
class Node{
    int value;
    Node left;
    Node right;

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

    //Override toString method

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

    //Middle order traversal
    public void infixOrder(){
        if(this.left != null){
            this.left.infixOrder();
        }

        System.out.println(this);

        if(this.right != null){
            this.right.infixOrder();
        }
    }

    //Add node
    public void add(Node node){
        //Handling special situations
        if(node == null){ return; }

        //Judge node Value and this Value size relationship
        if(this.value > node.value){
            //Look left
            if(this.left == null){
                this.left = node;
            }else{
                this.left.add(node);
            }
        }else{
            //Look right
            if(this.right == null){
                this.right = node;
            }else{
                this.right.add(node);
            }
        }
    }

}

//Create a binary sort tree management node
class BinarySortTree{
    private Node root;

    public Node getRoot() {
        return root;
    }

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

    //Add node to binary tree
    public void add(Node node){
        if(root == null){
            this.root = node;
        }else{
            this.root.add(node);
        }
    }

    //Order traversal in binary tree
    public void infixOrder(){
        if(this.root != null){
            this.root.infixOrder();
        }else{
            System.out.println("Empty tree cannot be traversed");
        }
    }

}
public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int[] array = new int[]{7, 3, 10, 12, 5, 1, 9};

        //Create a binary tree object
        BinarySortTree bst = new BinarySortTree();
        //Add node object
        for(Integer temp:array){
            bst.add(new Node(temp));
        }

        //Middle order traversal
        System.out.println("Middle order traversal:----");
        bst.infixOrder();

    }
}

Middle order traversal:----
Node{value=1}
Node{value=3}
Node{value=5}
Node{value=7}
Node{value=9}
Node{value=10}
Node{value=12}

Binary sort tree deletion

The deletion of binary sort tree is complex. There are three situations to consider:

  • Delete leaf node
  • Delete a node with only one subtree
  • Delete a node with two subtrees

Train of thought analysis:

Delete leaf node

  • You need to find the targetNode of the node to be deleted first
  • Find the parent node of targetNode
  • Determine whether the targetNode is the left child node or the right child node of the parent
  • Delete according to the previous situation

Delete a node with only one subtree

  • You need to find the targetNode of the node to be deleted first
  • Find the parent node of targetNode
  • Determines whether the child node of the targetNode is a left child node or a right child node
  • Determines whether the child node of the targetNode is a left child node or a right child node
  • Delete according to the previous situation

Delete a node with two subtrees

  • You need to find the targetNode of the node to be deleted first
  • Find the parent node of targetNode
  • Find the smallest node from the right subtree of targetNode
  • Use a temporary variable to save the value of the smallest node to temp
  • Delete the minimum node
  • Assign the value of temp to targetNode
package com.atguigu.binarysorttree;

/**
 * @ClassName BinarySortTreeDemo
 * @Author Jeri
 * @Date 2022-02-26 17:58
 * @Description Creation, traversal and deletion of binary sort tree
 */

//Create node class object
class Node{
    int value;
    Node left;
    Node right;

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

    //Override toString method

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

    //Middle order traversal
    public void infixOrder(){
        if(this.left != null){
            this.left.infixOrder();
        }

        System.out.println(this);

        if(this.right != null){
            this.right.infixOrder();
        }
    }

    //Add node
    public void add(Node node){
        //Handling special situations
        if(node == null){ return; }

        //Judge node Value and this Value size relationship
        if(this.value > node.value){
            //Look left
            if(this.left == null){
                this.left = node;
            }else{
                this.left.add(node);
            }
        }else{
            //Look right
            if(this.right == null){
                this.right = node;
            }else{
                this.right.add(node);
            }
        }
    }

    //Find the node to be deleted
    public Node search(int value){
        if(this.value == value){
            return this;
        }else if(this.value > value){
            //Left recursive search
            if(this.left == null){
                return null;
            }
            return this.left.search(value);
        }else{
            //Recursive right
            if(this.right == null){
                return null;
            }

            return this.right.search(value);
        }
    }

    //Find the parent node of the node to be deleted
    public Node searchParent(int value){
        //Judge the current node
        if((this.left != null && this.left.value == value) ||
                (this.right != null && this.right.value == value)){
            return this;
        }else{
            //The left child node of the current node is not empty and the value is greater than the lookup value
            if(this.left != null && this.value > value){
                return this.left.searchParent(value);
            }else if(this.right != null && this.value < value){
                //The right child node of the current node is not empty and the value is less than the lookup value
                return this.right.searchParent(value);
            }else{
                //Parent node not found
                return  null;
            }
        }
    }



}

//Create a binary sort tree management node
class BinarySortTree{
    private Node root;

    public Node getRoot() {
        return root;
    }

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

    //Add node to binary tree
    public void add(Node node){
        if(root == null){
            this.root = node;
        }else{
            this.root.add(node);
        }
    }

    //Order traversal in binary tree
    public void infixOrder(){
        if(this.root != null){
            this.root.infixOrder();
        }else{
            System.out.println("Empty tree cannot be traversed");
        }
    }

    //Binary tree to find the node to be deleted
    public Node search(int value){
        if(root == null){
            return null;
        }else{
            return this.root.search(value);
        }
    }

    //Parent tree of node to be deleted
    public Node searchParent(int value){
        if(root == null){
            return null;
        }else{
            return this.root.searchParent(value);
        }
    }

    //Binary tree finds the smallest node with the current node as the root node
    public int delRightTreeMin(Node node){
        Node target = node;
        //Binary sort tree can find the left node circularly
        while(target.left != null){
            target = target.left;
        }

        //The smallest node is found when you exit the loop
        //Delete minimum node
        deleteNode(target.value);
        return target.value;
    }



    //Delete node from binary tree
    public void deleteNode(int value){
        if(this.root == null){
            return;
        }else{
            //Find the node to be deleted
            Node targetNode = search(value);
            //No node to be deleted found
            if(targetNode == null){
                return;
            }

            //The following code defaults to targetnode= null
            if(this.root.left == null && this.root.right == null){
                //targetNode == root
                root = null;
                return;
            }

            //The following code defaults to targetnode= null && targetNode !=  root

            //Find the parent node of targetNode
            Node parent = searchParent(value);

            if(targetNode.left == null && targetNode.right == null){
                //The node to be deleted is a leaf node

                //Judge the relationship between the current node and the parent node
                if(parent.left != null && parent.left.value == value){
                    //Left child node
                    parent.left = null;
                }else if(parent.right != null && parent.right.value == value){
                    //Right child node
                    parent.right = null;
                }
            }else if(targetNode.left != null && targetNode.right != null){
                //There are left and right subtrees for the node to be deleted
                int minValue = delRightTreeMin(targetNode.right);
                targetNode.value = minValue;
            }else{
                //The node to be deleted has left subtree or right subtree
                if(targetNode.left != null){
                    //The node to be deleted has a left subtree
                    if(parent != null){
                        if(parent.left.value == value){
                            parent.left = targetNode.left;
                        }else{
                            parent.right = targetNode.left;
                        }
                    }else{
                        root = targetNode.left;
                    }
                }else{
                    //The node to be deleted has a right subtree
                    if(parent != null){
                        if(parent.left.value == value){
                            parent.left = targetNode.right;
                        }else{
                            parent.right = targetNode.right;
                        }
                    }else{
                        root = targetNode.right;
                    }
                }
            }
        }
    }

}
public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int[] array = new int[]{7, 3, 10, 12, 5, 1, 9};

        //Create a binary tree object
        BinarySortTree bst = new BinarySortTree();
        //Add node object
        for(Integer temp:array){
            bst.add(new Node(temp));
        }

        //Middle order traversal
        System.out.println("Middle order traversal:----");
        bst.infixOrder();

        //Test delete leaf node
        bst.deleteNode(1);
        bst.deleteNode(5);
        bst.deleteNode(10);
        bst.deleteNode(12);
        bst.deleteNode(3);
        bst.deleteNode(9);
        bst.deleteNode(7);

        System.out.println("After deleting a node:------");
        bst.infixOrder();
    }
}

Middle order traversal:----
Node{value=1}
Node{value=3}
Node{value=5}
Node{value=7}
Node{value=9}
Node{value=10}
Node{value=12}
After deleting a node:------
Empty tree cannot be traversed

Balanced binary tree

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

Analysis of problems in BST

  • The left subtree is all empty. From the formal point of view, it is more like a single linked list
  • Insertion speed has no effect
  • The query speed is significantly reduced (because it needs to be compared in turn), which can not give full play to the advantages of BST

It needs to be solved by using balanced binary (search) tree

Basic introduction:

Balanced binary tree is also called self balancing binary search tree, also known as 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 both the left and right subtrees are a balanced binary tree. Adding and deleting may require rebalancing the tree through one or more tree rotations

The common implementation methods of balanced binary tree include red black tree, AVL, scapegoat tree, tree, extension tree and so on

Application case - left rotation

Requirements: give you a sequence of numbers and create the corresponding balanced binary tree Sequence {4,3,6,5,7,8}

Train of thought analysis

Note: insert the left subtree of node 6 to the right of node 4, and set node 6 as the root node

    //Take this as the root node to rotate the binary tree to the left
    public void leftRotate(){
        //Create a new node attribute, which is the attribute of the root node of the current binary tree
        Node newNode = new Node(this.value);
        //The left subtree of the new node is set as the left subtree of the current node
        newNode.left = this.left;
        //The right subtree of the new node is set as the left subtree of the right subtree of the current node
        newNode.right = this.right.left;
        //Replace the attribute of the current node with the attribute of the right child node
        this.value = this.right.value;
        //The right subtree of the current node is set as the right subtree of the right subtree of the current node
        this.right = this.right.right;
        //The left subtree of the current node is set as the new node
        this.left = newNode;
    }

Application case - right rotation

Requirements: give you a sequence of numbers to create the corresponding balanced binary tree Sequence {10,12,8,9,7,6}

Train of thought analysis:

Note: insert the right subtree of node 8 to the left of node 10, and set node 8 as the root node

//Rotate the binary tree right with this as the root node
    public void rightRotate(){
        //Create a new node attribute and set it as the attribute of the root node of the current binary tree
        Node newNode = new Node(this.value);
        //The right subtree of the new node is set as the right subtree of the current node
        newNode.right = this.right;
        //The left subtree of the new node is set as the right subtree of the left subtree of the current node
        newNode.left = this.left.right;
        //Replace the attributes of the current node with the attributes of the left child node
        this.value = this.left.value;
        //The left subtree of the current node is set as the left subtree of the left subtree of the current node
        this.left = this.left.left;
        //The right subtree of the current node is set as the new node
        this.right = newNode;
    }

Application case - double rotation

Problem: in some cases, single rotation cannot complete the conversion of balanced binary tree
int[] arr = { 10, 11, 7, 6, 8, 9 }; Running the original code, you can see that it is not converted into AVL tree
int[] arr = {2,1,6,5,7,3}; // Running the original code, you can see that it is not converted into AVL tree


resolvent:

Int [] arr = {10, 11, 7, 6, 8, 9} insert node 9

  • When the binary tree with this as the root node satisfies the right rotation
  • Check: the height of the right subtree of the left subtree of this is greater than the height of the left subtree of the left subtree of this
  • First, rotate the left subtree of this
  • Then rotate this right

int[] arr = {2,1,6,5,7,3} insert node 3

  • When the binary tree with this as the root node satisfies the left rotation
  • Check: the height of the left subtree of the right subtree of this is greater than the height of the right subtree of the right subtree of this
  • First rotate the right subtree of this
  • Then rotate this to the left

Code display:

package com.atguigu.avl;

import java.util.Arrays;

/**
 * @ClassName AVLTreeDemo
 * @Author Jeri
 * @Date 2022-02-27 10:14
 * @Description Construction of balanced binary tree
 */

//Create node class
class Node{
    int value;
    Node left;
    Node right;

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

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

    //Middle order traversal
    public void infixOrder(){
        if(this.left != null){
            this.left.infixOrder();
        }

        System.out.println(this);

        if(this.right != null){
            this.right.infixOrder();
        }
    }

    //Add node
    public void add(Node node){
        //Handling special situations
        if(node == null){
            return;
        }

        //Judge node Value and this Value size relationship
        if(this.value > node.value){
            //Add left
            if(this.left == null){
                this.left = node;
            }else{
                this.left.add(node);
            }

        }else{
            //Add right
            if(this.right == null){
                this.right = node;
            }else{
                this.right.add(node);
            }
        }

        //Balance after adding nodes
        if(this.leftHeight() - this.rightHeight() > 1){
            //(height of left subtree - height of right subtree) > 1 rotate right
            if(this.left != null &&
                    this.left.rightHeight() > this.left.leftHeight()){
                //The height of the right subtree of the left subtree of this > the height of the left subtree of the left subtree of this

                //Rotate the left subtree of this
                this.left.leftRotate();

                //this makes a right rotation
                this.rightRotate();
            }else{
                //this makes a right rotation
                this.rightRotate();
            }

            return;
        }

        if(this.rightHeight() - this.leftHeight() > 1){
            //(height of right subtree - height of left subtree) > 1 rotate left
            if(this.right != null &&
                    this.right.leftHeight() > this.right.rightHeight()){
                //The height of the left subtree of the right subtree of this > the height of the right subtree of the right subtree of this

                //Right rotation of the right subtree of this
                this.right.rightRotate();

                //Rotate this left
                this.leftRotate();
            }else{
                //Rotate this left
                this.leftRotate();
            }

            return;
        }
    }

    //Returns the height of the tree with this as the root node
    public int height(){
        return Math.max(this.left == null?0:this.left.height(),
                this.right == null?0:this.right.height()) + 1;
    }

    //Returns the height of the left subtree with this as the root node
    public int leftHeight(){
        if(this.left == null){
            return 0;
        }
        return this.left.height();
    }

    //Returns the height of the right subtree with this as the root node
    public int rightHeight(){
        if(this.right == null){
            return 0;
        }
        return this.right.height();
    }

    //Take this as the root node to rotate the binary tree to the left
    public void leftRotate(){
        //Create a new node attribute, which is the attribute of the root node of the current binary tree
        Node newNode = new Node(this.value);
        //The left subtree of the new node is set as the left subtree of the current node
        newNode.left = this.left;
        //The right subtree of the new node is set as the left subtree of the right subtree of the current node
        newNode.right = this.right.left;
        //Replace the attribute of the current node with the attribute of the right child node
        this.value = this.right.value;
        //The right subtree of the current node is set as the right subtree of the right subtree of the current node
        this.right = this.right.right;
        //The left subtree of the current node is set as the new node
        this.left = newNode;

    }

    //Rotate the binary tree right with this as the root node
    public void rightRotate(){
        //Create a new node attribute and set it as the attribute of the root node of the current binary tree
        Node newNode = new Node(this.value);
        //The right subtree of the new node is set as the right subtree of the current node
        newNode.right = this.right;
        //The left subtree of the new node is set as the right subtree of the left subtree of the current node
        newNode.left = this.left.right;
        //Replace the attributes of the current node with the attributes of the left child node
        this.value = this.left.value;
        //The left subtree of the current node is set as the left subtree of the left subtree of the current node
        this.left = this.left.left;
        //The right subtree of the current node is set as the new node
        this.right = newNode;
    }

}

//Create balance tree
class AVLTree{
    private Node root;

    public Node getRoot() {
        return root;
    }

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

    //Add node to balance tree
    public void add(Node node){
        if(this.root == null){
            this.root = node;
        }else{
            this.root.add(node);
        }
    }

    //Order traversal in balanced tree
    public void infixOrder(){
        if(this.root == null){
            System.out.println("Empty tree cannot be traversed");
        }else{
            this.root.infixOrder();
        }
    }
}
public class AVLTreeDemo {
    public static void main(String[] args) {
        //int[] arr = {4,3,6,5,7,8};
        //int[] arr = {2,1,6,5,7,3};
        int[] arr = { 10, 11, 7, 6, 8, 9 };

        System.out.println("Original array:-----");
        System.out.println(Arrays.toString(arr));
        //Create an AVLTree object
        AVLTree avlTree = new AVLTree();

        //Add node
        for(int i=0; i < arr.length; i++) {
            avlTree.add(new Node(arr[i]));
        }

        //ergodic
        System.out.println("Middle order traversal");
        avlTree.infixOrder();

        System.out.println("In balance processing~~");
        System.out.println("Current root node=" + avlTree.getRoot());
        System.out.println("Height of tree=" + avlTree.getRoot().height());
        System.out.println("Height of the left subtree of the tree=" + avlTree.getRoot().leftHeight());
        System.out.println("Height of right subtree of tree=" + avlTree.getRoot().rightHeight());


    }
}
Original array:-----
[10, 11, 7, 6, 8, 9]
Middle order traversal
Node{value=6}
Node{value=7}
Node{value=8}
Node{value=9}
Node{value=10}
Node{value=11}
In balance processing~~
Current root node=Node{value=8}
Height of tree=3
 Height of the left subtree of the tree=2
 Height of right subtree of tree=2
Original array:-----
[2, 1, 6, 5, 7, 3]
Middle order traversal
Node{value=1}
Node{value=2}
Node{value=3}
Node{value=5}
Node{value=6}
Node{value=7}
In balance processing~~
Current root node=Node{value=5}
Height of tree=3
 Height of the left subtree of the tree=2
 Height of right subtree of tree=2

reference

Java data structure and Java algorithm

Keywords: Algorithm data structure

Added by jefffan24 on Sun, 27 Feb 2022 05:43:02 +0200