Day21 binary tree quick start learning (Java)

Posted by Garth Farley on Mon, 24 Jan 2022 04:35:56 +0100

1, Why use a tree as a data structure

1) Analysis of array storage mode

Advantages: it is fast to access elements by subscript. For ordered arrays, binary search can also be used to improve the retrieval speed.

Disadvantages: if a specific value is to be retrieved, or the inserted value (in a certain order) will move as a whole, which is inefficient [schematic]

2) Analysis of chain storage mode

Advantages: to a certain extent, the array storage mode is optimized (for example, if you insert a numerical node, you only need to link the inserted node to the linked list, and the deletion efficiency is also very good).

Disadvantages: when searching, the efficiency is still low, for example (to search a value, you need to traverse from the beginning of the node) [schematic diagram]

3) Analysis of tree storage mode

It can improve the efficiency of data storage and reading. For example, using binary sort tree can not only ensure the speed of data retrieval, but also ensure the speed of data insertion, deletion and modification.

[schematic diagram, detailed later]

Case: [7, 3, 10, 1, 5, 9, 12]

2, What is a binary tree

Binary tree diagram

concept

3, Preorder traversal of binary tree

Traversal description

Preorder traversal: first output the parent node, and then traverse the left and right subtrees

Middle order traversal: first traverse the left subtree, then output the parent node, and then traverse the right subtree

Post order traversal: first traverse the left subtree, then traverse the right subtree, and finally output the parent node

Summary: see the order of output parent nodes to determine whether it is pre order, middle order or post order

Traversal requirements

code implementation

package com.fafa.tree;

/**
 * Binary tree
 *
 * @author Sire
 * @version 1.0
 * @date 2022-01-22 16:51
 */
public class BinaryTreeDemo {
    public static void main(String[] args) {
        // Create node
        HeroNode root = new HeroNode(1, "Song Jiang");
        HeroNode node2 = new HeroNode(2, "Wu Yong");
        HeroNode node3 = new HeroNode(3, "Lu Junyi");
        HeroNode node4 = new HeroNode(4, "Lin Chong");
        HeroNode node5 = new HeroNode(5, "Wu Sheng");
        // Manually generate the binary tree first (it will be generated by recursion later, and manually for the time being)
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        // Create binary tree
        BinaryTree tree = new BinaryTree(root);
        // Test preorder traversal
        System.out.println("Preorder traversal");
        tree.preOrder();
        // Sequence traversal in test
        System.out.println("Medium order traversal");
        tree.infixOrder();
        // Post test traversal
        System.out.println("Postorder traversal");
        tree.postOrder();

    }

}

/**
 * Create binary tree
 */
class BinaryTree {

    HeroNode root = null;

    public BinaryTree(HeroNode root) {
        this.root = root;
    }

    /**
     * Preorder traversal
     */
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            System.out.println("This is an empty tree");
        }
    }

    /**
     * Medium order traversal
     */
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("This is an empty tree");
        }
    }

    /**
     * Postorder traversal
     */
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            System.out.println("This is an empty tree");
        }
    }


}

/**
 * Hero node
 */
class HeroNode {
    private int id;
    private String name;
    private HeroNode left;
    private HeroNode right;

    /**
     * Construction method. The left and right nodes are empty by default
     *
     * @param id
     * @param name
     */
    public HeroNode(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
    }

    /**
     * Preorder traversal
     * Idea:
     * 1,Reprint parent node
     * 2,Then judge whether the left subtree is empty. If not, print recursively
     * 3,Judge whether the right subtree is empty. If not, print recursively
     */
    public void preOrder() {
        // Why can you print directly without judging the root node? Because the transmitted node must be a valid node, you don't need to judge (it has been judged in the previous call layer)
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    /**
     * Medium order traversal
     * Idea:
     * 1,First judge whether the left subtree is empty. If not, print recursively
     * 2,Reprint parent node
     * 3,Judge whether the right subtree is empty. If not, print recursively
     */
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    /**
     * Postorder traversal
     * Idea:
     * 1,First judge whether the left subtree is empty. If not, print recursively
     * 2,Judge whether the right subtree is empty. If not, print recursively
     * 3,Reprint parent node
     */
    public void postOrder() {
        if (this.left != null) {
            this.left.postOrder();
        }
        if (this.right != null) {
            this.right.postOrder();
        }
        System.out.println(this);
    }
}

4, Binary tree pre middle post order search

demand

code implementation

Add to the HeroNode class

/**
     * Preorder traversal search
     *
     * @param no number
     * @return
     */
public HeroNode preOrderSearch(int no) {
    System.out.println("get into preSearch~");
    // Compare whether the current node is
    if (this.getId() == no) {
        return this;
    }
    // Result node
    HeroNode resNode = null;
    // Compare left child nodes
    // And traversal
    // 1. Judge whether the current self rating point is empty. If not, continue to traverse the search (recursion)
    // 2. If the left child node finds the result, it returns directly
    if (this.left != null) {
        resNode = this.left.preOrderSearch(no);
    }
    // If it is not empty, it indicates that it is found in the left subtree
    if (resNode != null) {
        return resNode;
    }
    // The same as above, except that the resNode can be returned directly in the end, because whether it is found or not, it is a resNode
    if (this.right != null) {
        resNode = this.right.preOrderSearch(no);
    }
    return resNode;
}

/**
     * Middle order traversal search
     *
     * @param no number
     * @return
     */
public HeroNode infixOrderSearch(int no) {
    // Result node
    HeroNode resNode = null;
    // Compare left child nodes
    // And traversal
    // 1. Judge whether the current self rating point is empty. If not, continue to traverse the search (recursion)
    // 2. If the left child node finds the result, it returns directly
    if (this.left != null) {
        resNode = this.left.infixOrderSearch(no);
    }
    // If it is not empty, it indicates that it is found in the left subtree
    if (resNode != null) {
        return resNode;
    }
    // It should be placed in front of the comparison statement, not just in the front (because it counts the comparison times)
    System.out.println("get into infixSearch~");
    // Compare whether the current node is
    if (this.getId() == no) {
        return this;
    }
    // The same as above, except that the resNode can be returned directly in the end, because whether it is found or not, it is a resNode
    if (this.right != null) {
        resNode = this.right.infixOrderSearch(no);
    }
    return resNode;
}

/**
     * Postorder traversal search
     *
     * @param no number
     * @return
     */
public HeroNode postOrderSearch(int no) {

    // Result node
    HeroNode resNode = null;
    // Compare left child nodes
    // And traversal
    // 1. Judge whether the current self rating point is empty. If not, continue to traverse the search (recursion)
    // 2. If the left child node finds the result, it returns directly
    if (this.left != null) {
        resNode = this.left.postOrderSearch(no);
    }
    // If it is not empty, it indicates that it is found in the left subtree
    if (resNode != null) {
        return resNode;
    }
    // The same as above, except that the resNode can be returned directly in the end, because whether it is found or not, it is a resNode
    if (this.right != null) {
        resNode = this.right.postOrderSearch(no);
    }
    if (resNode != null) {
        return resNode;
    }
    // It should be placed in front of the comparison statement, not just in the front (because it counts the number of comparisons)
    System.out.println("get into postSearch~");
    // If the left and right subtrees are not found
    if (this.getId() == no) {
        return this;
    }
    return null;
}

5, Delete node from binary tree

requirement

code implementation

Add in the HeroNode class

/**
     * Recursively delete nodes
     * 1,If the node to be deleted is a leaf node, you can delete the node directly
     * 2,If the deleted node is a non leaf node, the subtree is deleted
     */
public void delNode(int no) {
    //thinking
    /*
		 * 	1. Because our binary tree is unidirectional, we judge whether the child node of the current node needs to be deleted, but not whether the current node needs to be deleted
			2. If the left child node of the current node is not empty and the left child node is to delete the node, set this left = null;  And return (end recursive deletion)
			3. If the right child node of the current node is not empty and the right child node is to delete the node, set this right= null ; And return (end recursive deletion)
			4. If the node is not deleted in steps 2 and 3, we need to delete it recursively to the left subtree
			5.  If the node is not deleted in step 4, it should be deleted recursively to the right subtree

		 */
    if (this.left != null && this.left.getId() == no) {
        // Leave blank
        this.setLeft(null);
        return;
    }
    if (this.right != null && this.right.getId() == no) {
        this.setRight(null);
        return;
    }
    if (this.left != null) {
        this.left.delNode(no);
    }
    if (this.right != null) {
        this.right.delNode(no);
    }
}

Add in BinaryTree class

/**
     * Delete node
     * @param no
     */
public void delNode(int no) {
    if (root != null) {
        // This determines whether the node to be deleted is the root node
        if (root.getId() == no) {
            root = null;
        } else {
            root.delNode(no);
        }
    } else {
        System.out.println("Empty number, unable to delete~");
    }
}

After class thinking

Topics: Java data structure linked list