The tree

Before we talk about binary trees, what is a tree

The definition of the tree

  1. Tree is a very important data structure in our computer. It can describe many things in real life, such as family tree, organization structure of unit, and so on.

  2. A tree is a set of hierarchical relationships composed of N (n>=1) finite nodes. It’s called a tree because it looks like an upside down tree, meaning it has roots up and leaves down.

Trees here

The characteristics of the tree

  1. Each node has zero or more children;
  2. A node with no parent is a root node;
  3. Each non-root node has only one parent;
  4. Each node and its descendants can be viewed as a tree, called a subtree of the parent of the current node;

Terminology for trees

Degree of node:

The number of subtrees a node contains is called the degree of the node;

Leaf node:

Nodes with degree 0 are called leaf nodes, or they can be called terminal nodes

Branch node:

Nodes whose degree is not zero are called branch nodes or non-terminal nodes

Hierarchy of nodes:

Starting at the root, the level of the root is 1, the level of its immediate successor is 2, and so on

Sequence number of nodes:

The nodes in the tree are arranged in a linear sequence from top to bottom and from left to right in the same layer, and they are arranged into continuous natural numbers.

Tree degrees:

The maximum degree of all nodes in the tree

Tree height (depth) :

The maximum level of nodes in a tree

Forest:

M (m>=0) sets of non-intersecting trees. If the root node of a non-empty tree is deleted, the tree becomes a forest. Add a uniform root to a forest and it becomes a tree

Child node:

The immediate successors of a node are called the children of that node, e.g. (H is the child of D)

Parent (parent) :

The immediate precursor of a node is called the parent of that node, e.g. (D is the parent of H)

Sibling node:

Children of the same parent are called siblings, e.g. (I and J are siblings)

Now that you have a basic definition of a tree, let’s take a look at a special type of tree: binary trees

Binary tree

define

A binary tree is a tree with a degree of 2 or less.

graphic

Two special binary trees

Full binary tree

A binary tree is a full binary tree if the number of nodes at each level is maximized.

The number of nodes in each layer from the root is 1,2,4,8,16…. The rule is 2 to the n minus 1.

Complete binary tree

Leaf nodes can only appear at the lowest and lower levels, and the nodes at the lowest level are concentrated in the binary tree at the leftmost positions of the layer

Attention should be paid to the definition and judgment of full and complete binary trees

Ordinary binary tree creation

  1. We create it in the form of a linked list
  2. We need a node class to record the left subtree, right subtree, key, and value of the current node
private class Node {
        public Key key;/ / key
        public Value value;/ / value
        public Node left;// Left child
        public Node right;// Right child

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right; }}Copy the code
  1. Two variables are needed to record the root node and the number of elements in the tree
private Node root;/ / the root node
private int N;// The number of elements in the tree
Copy the code
  1. Define some way to create a binary tree

Insert data into the binary tree

  • Public void put(Key Key, Value Value): Insert a key-value pair into the tree (Call the overloaded PUT method below)
  • Public Node put(Node x,Key Key, Value Value) : Adds a key-value pair to the specified tree x and returns the new tree

Ideas:

2. The tree is not empty. Start from the root node and determine the key of the new node and the key of the current node. 2.1 If the key of the new node is larger than the key of the current node, continue to search for the right child of the current node. 2.2 If the key of the new node is smaller than the key of the current node, continue to search for the left child of the current node. 2.3 If the key of the new node is equal to the key of the current node, replace the value of the current nodeCopy the code

Code implementation:

public Node put(Node x, Key key, Value value) {
        if (x == null) {/ / tree is empty
            N++;
            return new Node(key, value, null.null);
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key of the new node is larger than the key of the current node, continue to find the right child of the current node
            x.right = put(x.right, key, value);
        } else if (cmp < 0) {// If the key of the new node is smaller than the key of the current node, continue to find the left child of the current node
            x.left = put(x.left, key, value);
        } else {// If the new node's key is the same as the current node's key, replace the current node's value
            x.value = value;
        }
        return x;
    }
Copy the code

Find the value of the key from the tree

  • Public Value get(Key Key) : find the Value of the Key from the tree (Call the overloaded GET method below)
  • Public Value get(Node x, Key Key): searches for the Value of the Key in the specified tree X

Ideas:

2. If the tree is not empty, start traversing from the root node to determine the key size of the node to be searched and the key size of the current node. 2.1 If the key of the node to be searched is larger than that of the current node, 2.2 If the key of the node to be searched is smaller than the key of the current node, the left child of the current node is searched. 2.3 If the key of the node to be searched is equal to the key of the current node, the value of the current node is returnedCopy the code

Code implementation:

    public Value get(Node x, Key key) {
        // The tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            return get(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            return get(x.left, key);
        } else {// Replace the value of the current node with the value of the current node
            returnx.value; }}Copy the code

Deletes the value of key from the tree

  • Public void delete(Key Key): deletes the value of the Key from the tree (Call the delete method overloaded below)
  • Public Node delete(Node x, Key Key): deletes the value of the Key in the specified tree X

Ideas:

1. Find the node to be deleted (same as get method), reduce the number of elements by 1 2. Find the smallest node in the right subtree of the node to be deleted minNode 2.1 Consider possible locations of the node to be deleted 2.1.1 The node to be deleted has no left child node 2.1.2 The node to be deleted has no right child node 2.1.3 The node to be deleted has left child node and right child node 3. Delete the smallest node in the right subtree 4. Make the left subtree of the deleted node the left subtree of the minNode, and make the right subtree of the deleted node the right subtree of the minNode 5. Make the parent of the deleted node point to minNode, the smallest nodeCopy the code

Code implementation:

 public Node delete(Node x, Key key) {
        / / tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            x.right = delete(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            x.left = delete(x.left, key);
        } else {// If the current key is the same as the current key, the node to be deleted is found
            /* The number of elements to delete is reduced by 1. MinNode 1.1 Consider the possible location of the node to be deleted 1.1.1 The node to be deleted has no left child node 1.1.2 The node to be deleted has no right child node 1.1.3 The node to be deleted has left child node and right child node 2. Delete the smallest node in the right subtree. 3. Make the left subtree of the deleted node become the left subtree of minNode. Make the right subtree of the deleted node the right subtree of the minNode. Make the parent of the deleted node point to the smallest node minNode */
            // The number of elements is reduced by one
            N--;
            // The node to be deleted has no left child
            if (x.left == null) {
                return x.right;
            }
            // The node to be deleted has no right child node
            if (x.right == null) {
                return x.left;
            }
            // Find the smallest node in the right subtree of the node to be deleted
            Node minNode = x.right;
            // The smallest node in the right subtree of the node to be deleted is minNode
            while(minNode.left ! =null) {
                minNode = minNode.left;
            }
            // Delete the smallest node in the right subtree
            // Start from the right subtree of the node to be deleted and work your way to the left
            Node temp = x.right;
            while(temp.left ! =null) {
                if (temp.left.left == null) {
                    temp.left = null;// Delete is implemented here
                } else{ temp = temp.left; }}// make the left subtree of the deleted node the left subtree of the smallest node minNode
            minNode.left = x.left;
            // make the right subtree of the deleted node the right subtree of the smallest node minNode
            minNode.right = x.right;
            // Make the parent of the deleted node point to the smallest node minNode
            x = minNode;// Give x all the contents of minNode

        }

        return x;
Copy the code

Gets the number of elements in the tree

  • Public int size(): Gets the number of elements in the tree

Code implementation:

    // Get the number of elements in the tree
    public int size(a) {
        return N;
    }
Copy the code

Complete binary tree creation API

package com.study.tree;

import com.study.queue.queueAPI;

public class BinaryTreeAPI<Key extends Comparable<Key>, Value> {
    / / node class
    private class Node {
        public Key key;/ / key
        public Value value;/ / value
        public Node left;// Left child
        public Node right;// Right child

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right; }}private Node root;/ / the root node
    private int N;// The number of elements in the tree

    // Get the number of elements in the tree
    public int size(a) {
        return N;
    }

    // Add the key-value element to the entire tree
    // Call the overloaded method of put
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    /** * adds a key-value to the specified tree and returns the new tree * 1. If the tree is empty, the new node is used as the root node * 2. If the tree is not empty, judge the key of the new node and the key of the current node from the root node. * 2.1 If the key of the new node is larger than the key of the current node, continue to search for the right child of the current node * 2.2 If the key of the new node is smaller than the key of the current node, continue to search for the left child of the current node * 2.3 If the key of the new node is equal to the key of the current node, Replace the value */ of the current node
    public Node put(Node x, Key key, Value value) {
        if (x == null) {/ / tree is empty
            N++;
            return new Node(key, value, null.null);
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key of the new node is larger than the key of the current node, continue to find the right child of the current node
            x.right = put(x.right, key, value);
        } else if (cmp < 0) {// If the key of the new node is smaller than the key of the current node, continue to find the left child of the current node
            x.left = put(x.left, key, value);
        } else {// If the new node's key is the same as the current node's key, replace the current node's value
            x.value = value;
        }
        return x;
    }

    // Query the value of the specified key in the entire tree
    public Value get(Key key) {
        return get(root, key);
    }

    // In the specified tree x, find the corresponding value of key
    public Value get(Node x, Key key) {
        // The tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            return get(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            return get(x.left, key);
        } else {// Replace the value of the current node with the value of the current node
            returnx.value; }}// Delete the value corresponding to the key in the tree
    public void delete(Key key) {
        delete(root, key);
    }

    /** * removes the value corresponding to the key in the specified tree and returns the deleted new tree * 1. Find the deleted node; * 2. Find the smallest node minNode * 3 in the right subtree of the deleted node. Delete the smallest node in the right subtree * 4. Make the left subtree of the deleted node the left subtree of minNode, * make the right subtree of the deleted node the right subtree of minNode * 5. Make the parent of the deleted node point to the smallest node minNode */
    public Node delete(Node x, Key key) {
        / / tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            x.right = delete(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            x.left = delete(x.left, key);
        } else {// If the current key is the same as the current key, the node to be deleted is found
            /* The number of elements to delete is reduced by 1. MinNode 1.1 Consider the possible location of the node to be deleted 1.1.1 The node to be deleted has no left child node 1.1.2 The node to be deleted has no right child node 1.1.3 The node to be deleted has left child node and right child node 2. Delete the smallest node in the right subtree. 3. Make the left subtree of the deleted node become the left subtree of minNode. Make the right subtree of the deleted node the right subtree of the minNode. Make the parent of the deleted node point to the smallest node minNode */
            // The number of elements is reduced by one
            N--;
            // The node to be deleted has no left child
            if (x.left == null) {
                return x.right;
            }
            // The node to be deleted has no right child node
            if (x.right == null) {
                return x.left;
            }
            // Find the smallest node in the right subtree of the node to be deleted
            Node minNode = x.right;
            // The smallest node in the right subtree of the node to be deleted is minNode
            while(minNode.left ! =null) {
                minNode = minNode.left;
            }
            // Delete the smallest node in the right subtree
            // Start from the right subtree of the node to be deleted and work your way to the left
            Node temp = x.right;
            while(temp.left ! =null) {
                if (temp.left.left == null) {
                    temp.left = null;// Delete is implemented here
                } else{ temp = temp.left; }}// make the left subtree of the deleted node the left subtree of the smallest node minNode
            minNode.left = x.left;
            // make the right subtree of the deleted node the right subtree of the smallest node minNode
            minNode.right = x.right;
            // Make the parent of the deleted node point to the smallest node minNode
            x = minNode;// Give x all the contents of minNode

        }

        returnx; }}Copy the code

Maximum and minimum keys in a binary tree

Train of thought

Because we created it on the basis that the left subtree of the root is smaller than the root, and the right subtree of the root is larger than the root, so we go to the right subtree for the largest key, and we go to the left subtree for the smallest key

Method implementation (I also put these in the binary tree creation API)

    // Find the largest key in the tree
    public Key max(a) {
        Node minNode = root; // Use a new node for the purpose of preventing root from being modified
        / / tree is empty
        if (minNode == null) {
            return null;
        }
        // The tree is not empty
        while(minNode.right ! =null) {
            if (minNode.right.right == null) {
                return minNode.right.key;
            } else{ minNode = minNode.right; }}return minNode.key;
    }

    // Find the smallest key in the tree
    public Key min(a) {
        Node maxNode = root;
        / / tree is empty
        if (maxNode == null) {
            return null;
        }
        // The tree is not empty
        while(maxNode.left ! =null) {
            if (maxNode.left.left == null) {
                return maxNode.left.key;
            } else{ maxNode = maxNode.left; }}return maxNode.key;
    }
Copy the code

Traversal of binary trees

With the following binary tree traversal to illustrate three ordinary traversal and an advanced traversal

The former sequence traversal

Traverse order: root node -> left subtree -> right subtree

Ideas:

  1. Put the key of the current node into the queue
  2. Find the left subtree of the current node, if not empty, recursively traverse the left subtree
  3. Find the right subtree of the current node, if not empty, recursively traverse the right subtree
    // First access the root node, then the left subtree, then the right subtree
    // Get all keys of the entire tree
    public queueAPI<Key> preErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        preErgodic(root, queue);
        return queue;
    }

    // Get all the keys of the specified tree and put them in the queue
    public void preErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // put the key of node X into the queue
        queue.enqueue(x.key);

        // Recursively traverse the left subtree of x
        if(x.left ! =null) {
            preErgodic(x.left, queue);
        }
        // Recursively traverse the right subtree of x
        if(x.right ! =null) { preErgodic(x.right, queue); }}Copy the code

In the sequence traversal

Traversal order: left subtree -> root node -> right subtree

Ideas:

  1. Find the left subtree of the current node, if not empty, recursively traverse the left subtree
  2. Put the key of the current node into the queue;
  3. Find the right subtree of the current node, if not empty, recursively traverse the right subtree
     // Middle traversal: first access the left subtree, then access the root, then access the right subtree
    public queueAPI<Key> midErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        midErgodic(root, queue);
        return queue;
    }

    public void midErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // Recursively traverse the left subtree, looking for the leftmost element
        if(x.left ! =null) {
            midErgodic(x.left, queue);
        }
        // when x. eft equals null, the current node x is the leftmost element and is added directly to the queue
        queue.enqueue(x.key);
        // Recursively traverse the right subtree
        if(x.right ! =null) { midErgodic(x.right, queue); }}Copy the code

After the sequence traversal

Traversal order: left subtree -> right subtree -> root node

Ideas:

  1. Find the left subtree of the current node, if not empty, recursively traverse the left subtree
  2. Find the right subtree of the current node, if not empty, recursively traverse the right subtree
  3. Put the key of the current node into the queue;
    // Order traversal: first access the left subtree, then access the right subtree, then access the root
    public queueAPI<Key> afterErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        afterErgodic(root, queue);
        return queue;
    }

    public void afterErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // Recursively traverse the left subtree
        if(x.left ! =null) {
            afterErgodic(x.left, queue);
        }
        // Recursively traverse the right subtree
        if(x.right ! =null) {
            afterErgodic(x.right, queue);
        }
        // when x. eft equals null, yes, the current node x is the leftmost element and is added directly to the queue
        queue.enqueue(x.key);

    }
Copy the code

Sequence traversal

Traversal order: start from the root node (the first layer) and then go down to obtain the values of all nodes of each layer.

Ideas:

  1. Create a queue to store nodes, putting the head node in first
  2. Each time a node in the queue is popped, the key of the node is obtained
  3. See if the node that pops up has a left child and put it in if it does
  4. See if the node that pops up has a right child and put it in if it does

The illustration

public queueAPI<Key> layerErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();// Store sorted elements
        queueAPI<Node> nodes = new queueAPI<>();// Store the node
        // Put the first node into the node queue
        nodes.enqueue(root);
        // Iterate over the Nodes queue
        while(! nodes.isEmpty()){// Pop the first node in the queue each time
            Node node = nodes.dequeue();
            // Put the key of the pop-up node into the sorted queue
            queue.enqueue(node.key);
            // Check whether the popup node has a left child node. If so, add it to the node queue
            if(node.left! =null){
                nodes.enqueue(node.left);
            }
            // See if the node that pops up has a right child node. If it does, add it to the node queue
            if(node.right! =null){ nodes.enqueue(node.right); }}return queue;
    }
Copy the code

The depth of a binary tree

Depth: The number of nodes along the longest path from the root node of the tree to the farthest leaf node

Ideas:

  1. If the root is empty, the maximum depth is 0.
  2. Calculate the maximum depth of the left subtree;
  3. Calculate the maximum depth of the right subtree;
  4. The maximum depth of the current tree = the greater of the maximum depth of the left subtree and the maximum depth of the right subtree +1

Code implementation:

 public int maxDepth(a){
        return maxDepth(root);
    }
    // Find the maximum depth of the tree
    public int maxDepth(Node x){
        if (x==null) {return 0;
        }
        int left = 0; // The maximum depth of the left subtree
        int right = 0; // The maximum depth of the right subtree
        int max = 0; // The larger of the left and right subtrees
        if(x.left! =null) {// Calculate the maximum depth of the left subtree;
            left=maxDepth(x.left);
        }
        if(x.right! =null) {// Calculate the maximum depth of the right subtree;right = maxDepth(x.right); } max = left>right? left+1:right+1;
        return max;

    }
Copy the code

Binary tree summary

The above method implementation is summarized into a binary tree implementation API, the total code is:

package com.study.tree;

import com.study.queue.queueAPI;

public class BinaryTreeAPI<Key extends Comparable<Key>, Value> {
    private Node root;/ / the root node
    private int N;// The number of elements in the tree

    // Get the number of elements in the tree
    public int size(a) {
        return N;
    }

    // Add the key-value element to the entire tree
    // Call the overloaded method of put
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    /** * adds a key-value to the specified tree and returns the new tree * 1. If the tree is empty, the new node is used as the root node * 2. If the tree is not empty, judge the key of the new node and the key of the current node from the root node. * 2.1 If the key of the new node is larger than the key of the current node, continue to search for the right child of the current node * 2.2 If the key of the new node is smaller than the key of the current node, continue to search for the left child of the current node * 2.3 If the key of the new node is equal to the key of the current node, Replace the value */ of the current node
    public Node put(Node x, Key key, Value value) {
        if (x == null) {/ / tree is empty
            N++;
            return new Node(key, value, null.null);
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key of the new node is larger than the key of the current node, continue to find the right child of the current node
            x.right = put(x.right, key, value);
        } else if (cmp < 0) {// If the key of the new node is smaller than the key of the current node, continue to find the left child of the current node
            x.left = put(x.left, key, value);
        } else {// If the new node's key is the same as the current node's key, replace the current node's value
            x.value = value;
        }
        return x;
    }

    // Query the value of the specified key in the entire tree
    public Value get(Key key) {
        return get(root, key);
    }

    // In the specified tree x, find the corresponding value of key
    public Value get(Node x, Key key) {
        // The tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            return get(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            return get(x.left, key);
        } else {// Replace the value of the current node with the value of the current node
            returnx.value; }}// Delete the value corresponding to the key in the tree
    public void delete(Key key) {
        delete(root, key);
    }

    /** * removes the value corresponding to the key in the specified tree and returns the deleted new tree * 1. Find the deleted node; * 2. Find the smallest node minNode * 3 in the right subtree of the deleted node. Delete the smallest node in the right subtree * 4. Make the left subtree of the deleted node the left subtree of minNode, * make the right subtree of the deleted node the right subtree of minNode * 5. Make the parent of the deleted node point to the smallest node minNode */
    public Node delete(Node x, Key key) {
        / / tree is empty
        if (x == null) {
            return null;
        }
        // The tree is not empty
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {// If the key is larger than the current key, continue to search for the right child of the current node
            x.right = delete(x.right, key);
        } else if (cmp < 0) {// If the key is smaller than the key of the current node, continue to find the left child of the current node
            x.left = delete(x.left, key);
        } else {// If the current key is the same as the current key, the node to be deleted is found
            /* The number of elements to delete is reduced by 1. MinNode 1.1 Consider the possible location of the node to be deleted 1.1.1 The node to be deleted has no left child node 1.1.2 The node to be deleted has no right child node 1.1.3 The node to be deleted has left child node and right child node 2. Delete the smallest node in the right subtree. 3. Make the left subtree of the deleted node become the left subtree of minNode. Make the right subtree of the deleted node the right subtree of the minNode. Make the parent of the deleted node point to the smallest node minNode */
            // The number of elements is reduced by one
            N--;
            // The node to be deleted has no left child
            if (x.left == null) {
                return x.right;
            }
            // The node to be deleted has no right child node
            if (x.right == null) {
                return x.left;
            }
            // Find the smallest node in the right subtree of the node to be deleted
            Node minNode = x.right;
            // The smallest node in the right subtree of the node to be deleted is minNode
            while(minNode.left ! =null) {
                minNode = minNode.left;
            }
            // Delete the smallest node in the right subtree
            // Start from the right subtree of the node to be deleted and work your way to the left
            Node temp = x.right;
            while(temp.left ! =null) {
                if (temp.left.left == null) {
                    temp.left = null;// Delete is implemented here
                } else{ temp = temp.left; }}// make the left subtree of the deleted node the left subtree of the smallest node minNode
            minNode.left = x.left;
            // make the right subtree of the deleted node the right subtree of the smallest node minNode
            minNode.right = x.right;
            // Make the parent of the deleted node point to the smallest node minNode
            x = minNode;// Give x all the contents of minNode

        }

        return x;
    }

    // Find the largest key in the tree
    public Key max(a) {
        Node minNode = root; // Use a new node for the purpose of preventing root from being modified
        / / tree is empty
        if (minNode == null) {
            return null;
        }
        // The tree is not empty
        while(minNode.right ! =null) {
            if (minNode.right.right == null) {
                return minNode.right.key;
            } else{ minNode = minNode.right; }}return minNode.key;
    }

    // Find the smallest key in the tree
    public Key min(a) {
        Node maxNode = root;
        / / tree is empty
        if (maxNode == null) {
            return null;
        }
        // The tree is not empty
        while(maxNode.left ! =null) {
            if (maxNode.left.left == null) {
                return maxNode.left.key;
            } else{ maxNode = maxNode.left; }}return maxNode.key;
    }

    // First access the root node, then the left subtree, then the right subtree
    // Get all keys of the entire tree
    public queueAPI<Key> preErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        preErgodic(root, queue);
        return queue;
    }

    // Get all the keys of the specified tree and put them in the queue
    public void preErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // put the key of node X into the queue
        queue.enqueue(x.key);

        // Recursively traverse the left subtree of x
        if(x.left ! =null) {
            preErgodic(x.left, queue);
        }
        // Recursively traverse the right subtree of x
        if(x.right ! =null) { preErgodic(x.right, queue); }}// Middle traversal: first access the left subtree, then access the root, then access the right subtree
    public queueAPI<Key> midErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        midErgodic(root, queue);
        return queue;
    }

    public void midErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // Recursively traverse the left subtree, looking for the leftmost element
        if(x.left ! =null) {
            midErgodic(x.left, queue);
        }
        // when x. eft equals null, the current node x is the leftmost element and is added directly to the queue
        queue.enqueue(x.key);
        // Recursively traverse the right subtree
        if(x.right ! =null) { midErgodic(x.right, queue); }}// Order traversal: first access the left subtree, then access the right subtree, then access the root
    public queueAPI<Key> afterErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();
        afterErgodic(root, queue);
        return queue;
    }

    public void afterErgodic(Node x, queueAPI<Key> queue) {
        if (x == null) {
            return;
        }
        // Recursively traverse the left subtree
        if(x.left ! =null) {
            afterErgodic(x.left, queue);
        }
        // Recursively traverse the right subtree
        if(x.right ! =null) {
            afterErgodic(x.right, queue);
        }
        // when x. eft equals null, yes, the current node x is the leftmost element and is added directly to the queue
        queue.enqueue(x.key);

    }

    // sequence traversal
    // 1. Create a queue to store nodes
    // 2. Each time a node in the queue is popped,
    // 3. Check if the popup node has a left child node. If so, put it in
    // 4. Check if the popup node has a right child node, if so, put it in
    public queueAPI<Key> layerErgodic(a) {
        queueAPI<Key> queue = new queueAPI<>();// Store sorted elements
        queueAPI<Node> nodes = new queueAPI<>();// Store the node
        // Put the first node into the node queue
        nodes.enqueue(root);
        // Iterate over the Nodes queue
        while(! nodes.isEmpty()){// Pop the first node in the queue each time
            Node node = nodes.dequeue();
            // Put the key of the pop-up node into the sorted queue
            queue.enqueue(node.key);
            // Check whether the popup node has a left child node. If so, add it to the node queue
            if(node.left! =null){
                nodes.enqueue(node.left);
            }
            // See if the node that pops up has a right child node. If it does, add it to the node queue
            if(node.right! =null){ nodes.enqueue(node.right); }}return queue;
    }
    // Find the maximum depth of the whole tree
    // 1. Find the maximum depth of the left subtree
    // 2. Find the maximum depth of the right subtree
    // 3. Take the maximum value of left and right subtrees +1 as the depth
    public int maxDepth(a){
        return maxDepth(root);
    }
    // Find the maximum depth of the tree
    public int maxDepth(Node x){
        if (x==null) {return 0;
        }
        int left = 0; // The maximum depth of the left subtree
        int right = 0; // The maximum depth of the right subtree
        int max = 0; // The larger of the left and right subtrees
        if(x.left! =null){
            left=maxDepth(x.left);
        }
        if(x.right! =null){ right = maxDepth(x.right); } max = left>right? left+1:right+1;
        return max;

    }
    / / node class
    private class Node {
        public Key key;/ / key
        public Value value;/ / value
        public Node left;// Left child
        public Node right;// Right child

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right; }}}Copy the code

Let’s test the code again:

package com.study.tree;

import com.study.queue.queueAPI;

public class BinaryTreeTest {
    public static void main(String[] args) {
        BinaryTreeAPI<Integer, String> bt = new BinaryTreeAPI<>();
        bt.put(5."Zhang");
        bt.put(2."Bill");
        bt.put(7."Fifty");
        bt.put(1."Daisy");
        bt.put(4."Xin wu");
        bt.put(6."Zhao four");
        bt.put(8."Wu lei");
        bt.put(3."Lin");
        System.out.println("After adding elements, the total number of elements is:"+bt.size());
        System.out.println(bt.get(2));
        bt.delete(2);
        System.out.println("After deleting elements, the total number of elements is:"+bt.size());
        System.out.println("After the element is deleted, the value of the element with key 2 is:"+bt.get(2));
        bt.put(2."Bill");
        Integer min = bt.min();
        System.out.println(The element with the smallest bond is:+min);
        Integer max = bt.max();
        System.out.println("The largest element of the bond is:"+max);
        System.out.println("Sequential traversal:");
        queueAPI<Integer> prequeue = bt.preErgodic();
        for (Integer i : prequeue) {
            System.out.println(i+"-"+bt.get(i));
        }
        System.out.println(Middle order traversal:);
        queueAPI<Integer> queue = bt.midErgodic();
        for (Integer i : queue) {
            System.out.println(i+"-"+bt.get(i));
        }
        System.out.println("After traversal:");
        queueAPI<Integer> afqueue = bt.afterErgodic();
        for (Integer i : afqueue) {
            System.out.println(i+"-"+bt.get(i));
        }
        System.out.println("Sequence traversal:");
        queueAPI<Integer> layerqueue = bt.layerErgodic();
        for (Integer i : layerqueue) {
            System.out.println(i+"-"+bt.get(i));
        }
        int maxDepth = bt.maxDepth();
        System.out.println(The depth of the tree is:+maxDepth); }}Copy the code

Add an element to the tree, delete an element from the tree, and obtain the value of the specific key in the tree

The former sequence traversal

In the sequence traversal

After the sequence traversal

Sequence traversal

The depth of the tree