[Java data structure] - introduction of tree and detailed analysis of binary tree

Posted by gaz_hayes on Fri, 11 Feb 2022 09:56:28 +0100

1, Basic concepts of tree

Definition of tree:

Tree is a nonlinear data structure. It is a set with hierarchical relationship composed of n (n > = 0) finite nodes. It is called a tree because it looks like an upside down tree, that is, it has its roots up and its leaves down. It has the following characteristics:

  1. There is a special node, called the root node, which has no precursor node
  2. Except for the root node, the other nodes are divided into m (M > 0) disjoint sets T1, T2,..., Tm, and each set Ti (1 < = I < = m) is a subtree similar to the tree. The root node of each subtree has and has only one precursor, which can have 0 or more successors
  3. Trees are recursively defined.


**[note] * * in the tree structure, there can be no intersection between subtrees, otherwise it is not a tree structure, as shown in the following figure:

The following are the important concepts of trees:
Take this tree as an example:

Degree of node: the number of subtrees in A node is called the degree of the node; As shown in the figure above: the degree of A is 6

Tree degree: the maximum degree of all nodes in a tree is called the degree of the tree; As shown in the figure above: the degree of the tree is 6

Leaf node or terminal node: the node with degree 0 is called leaf node; As shown in the figure above: nodes B, C, H, I... Are leaf nodes

Parent node or parent node: if a node contains child nodes, this node is called the parent node of its child nodes; As shown in the figure above: A is the parent node of B

Child node or child node: the root node of the subtree contained in a node is called the child node of the node; As shown in the figure above: B is the child node of A

Root node: A node in A tree without parent nodes; As shown in the figure above: A
The root of the second layer is the root of the second layer, and so on

Height or depth of tree: the maximum level of nodes in the tree; As shown in the figure above: the height of the tree is 4
The following concepts of tree only need to be understood. When reading, just know what it means

Non terminal node or branch node: the node whose degree is not 0; As shown in the figure above, nodes D, E, F, G... Are branch nodes

Sibling node: nodes with the same parent node are called sibling nodes; As shown in the figure above: B and C are sibling nodes

Cousin node: nodes where parents are on the same level are cousins to each other; As shown in the figure above, H and I are brother nodes of each other

Ancestor of a node: all nodes from the root to the branch through which the node passes; As shown in the figure above: A is the ancestor of all nodes

Descendant: any node in the subtree with a node as the root is called the descendant of the node. As shown in the figure above: all nodes are descendants of A

Forest: a collection of m (m > = 0) disjoint trees is called forest

2, Storage structure of tree

The tree structure is more complex than the linear table, and it is more troublesome to store and express. In fact, there are many kinds of tree representations, such as parent representation, child representation, child parent representation, child brother representation and so on. Let's briefly understand the most commonly used child brother expression.

class Node {
 int value; // Data stored in the tree 
 Node firstChild; // First child quote 
 Node nextBrother; // Next brother references}

3, Binary tree

3.1. Concept of binary tree

definition:

A binary tree is a finite set of n(n ≥ 0)] nodes. The set is either an empty set (called an empty Binary Tree) or consists of a root node and two disjoint left and right subtrees called root nodes respectively.

In short:
A binary tree is a finite set of nodes, which:

  1. Or empty
  2. Or it is composed of a root node plus two binary trees called left subtree and right subtree.
    As can be seen from the above figure:
  3. Binary tree does not have nodes with degree greater than 2
  4. The subtree of a binary tree can be divided into left and right, and the order cannot be reversed. Therefore, a binary tree is an ordered tree.

**[note] * * any binary tree is composed of the following situations:

Binary tree has five basic forms:

  1. Empty binary tree.
  2. There is only one root node.
  3. The root node has only the left subtree
  4. The root node has only the right subtree
  5. The root node has both left and right subtrees

3.2. Special binary tree

Full binary tree:

A binary tree is a full binary tree if the number of nodes in each layer reaches the maximum. In other words, if the number of layers of a binary tree is K and the total number of nodes is 2^k - 1, it is a full binary tree.

Characteristics of full binary tree:

  1. Leaves can only appear in the lowest layer. It is impossible to reach a balance when it appears in other layers.
  2. The degree of non leaf node must be 2.
  3. In the same depth of binary tree, the full binary tree has the most nodes and the most leaves.

Complete binary tree:

Complete binary tree: a complete binary tree is a highly efficient data structure. A complete binary tree is derived from a full binary tree. For depth K, there is n
A binary tree with two nodes is called complete if and only if each node corresponds to the nodes numbered from 0 to n-1 in the full binary tree with depth K
Full binary tree. It should be noted that full binary tree is a special kind of complete binary tree.

It is worth noting that a full binary tree must be a complete binary tree, but a complete binary tree is not necessarily a full binary tree.

Characteristics of complete binary tree:

(1) Leaf nodes can only appear in the bottom two layers.
(2) The lowest leaves must be concentrated in a continuous position on the left.
(3) On the penultimate floor, if there are leaf nodes, they must be in the continuous position on the right.
(4) If the node degree is 1, the node has only left children, that is, there is no case of only right subtree.
(5) For a binary tree with the same number of nodes, the depth of a complete binary tree is the smallest.

The way to judge whether a binary tree is a complete binary tree is to look at the schematic diagram of the tree and silently number each node layer by layer according to the structure of the full binary tree. If there is a gap in the number, it means that it is not a complete binary tree, otherwise it is.

As shown in the following figure, since the position of 10 does not exist, it is not a complete binary tree.

3.3. Properties of binary tree

Nature i: If the number of layers of the specified root node is 1, there are at most 2 ^ i-1 (i > 0) nodes on layer i of a non empty binary tree

As shown in the figure above:

The first layer is the root node. There is only one,
SO 2 ^ 1-1 = 20 = 1.
There are two on the second floor, 2 ^ 2-1 = 2 ^ 1 = 2.
There are four on the third floor, 2 ^ 3 - 1 = 2 ^ 2 = 4.
The fourth floor has eight 2 ^ 4 - 1 = 2 ^ 3 = 8.
Through the demonstration of data induction, it is easy to draw the conclusion that there are at most 2^i-1 nodes (I ≥ 1) on the i-layer of binary tree.

Property 2: if the depth of a binary tree with only root nodes is specified as 1, the maximum number of nodes of a binary tree with depth K is 2 ^ k - 1 (k > = 0).

Note that you must see clearly that it is 2^k minus 1, not 2k-1.

As shown in the figure above:
The depth is k, which means a binary tree with K layers. Let's take a look at the simple one first.
If there is one layer, at most 1 = 2 ^ 0 - 1 nodes.
If there are two layers, at most 1 + 2 = 3 = 2 ^ 2-1 nodes.
If there are three layers, at most 1 + 2 + 4 = 7 = 2 ^ 3-1 nodes.
If there are four layers, at most 1 + 2 + 4 + 8 = 15 = 2 ^ 4-1 nodes.
Through the demonstration of data induction, it can be concluded that if there are k layers, the binary tree has at most 2k-1 nodes.

Property 3: for any binary tree, if the number of leaf nodes is n0 and the number of non leaf nodes with degree 2 is n2, then n0 = n2 + 1.

Let's push it to:

1. Assuming that the number of nodes of the binary tree with degree 1 is n1, the number of nodes with degree 0 is n0, and the number of nodes with degree 2 is n2, then the total number of nodes of the binary tree is n=n0+n1+n2;

2. For any tree, if there are n nodes, n-1 edges will be generated.
n0: for nodes with 0 degree, only 0 edges can be generated downward;
n1: for a node with a degree of 1, only one edge can be generated downward. If there are n1 nodes, n1 edges will be generated;
n2: for nodes with degree 2, only 2 edges can be generated downward. If there are n2 nodes, 2*n2 edges will be generated.
Then we can get: n-1 = n1+2n2;

So: n0+n1+n2 = n1+2n2+1

Obtained: n0 = n2+1;

Property 4: the depth k of a complete binary tree with n nodes is [log2] (n+1) rounded up.

Why round up? for instance:

Property 5: for a complete binary tree with n nodes, if all nodes are numbered from 0 from top to bottom and from left to right, the nodes with sequence number i are:
If I > 0, parental serial number: (i-1)/2; i=0, I is the root node number, no parent node
If 2i+1 < n, left child serial number: 2i+1, otherwise there is no left child
If 2i+2 < n, right child serial number: 2i+2, otherwise there is no right child

Take the tree above as an example:

For the first one, it is obvious that i=1 is the root node. i> At 1, for example, at node 7, its parents are 7 / 2 = 3, and at node 9, its parents are [9 / 2] = 4.

For example, node 6, because 2 × 6 = 12 exceeds the total number of nodes 10, so node 6 has no left child. It is a leaf node. Similarly, node 5, because 2 × 5 = 10 is exactly the total number of nodes 10, so its left child is node 10.

Third, for example, node 5, because 2 × 5 + 1 = 11, which is greater than the total number of nodes 10, so it has no right child. And node 3, because 2 × 3 + 1 = 7 is less than 10, so its right child is node 7.

3.4. Storage structure of binary tree

The storage structure of binary tree is divided into sequential storage and chain storage similar to linked list.

Sequential storage is generally only used for complete binary trees.

Because sequential storage is not applicable, we consider using chain storage structure. Each node of a binary tree has at most two children, so it is a wise idea to design a data field and two pointer fields for it. We call such a linked list a binary linked list.

Where data is the data field, leftchild and rightchild are both pointer fields, which store pointers to left and right children respectively.

// Child representation
class Node { 
int val; // Data domain 
Node leftchild; // The reference of the left child often represents the whole left subtree with the left child as the root 
Node rightchild; // The reference of the right child often represents the whole right subtree with the right child as the root}

The binary tree of interview questions and written examination questions of many companies is basically in the form of child representation above.

3.5. Creation of binary tree

The following method to create a binary tree is a relatively simple one, which is not strictly correct or commonly used. In fact, the creation of binary tree is a very complex process.

class BTNode{
    public char val;
    public BTNode left;//Left child's quote
    public BTNode right;//Right child's reference
    public BTNode (char val){
        this.val=val;
    }
}
public class BinaryTree {
    public BTNode root;//Root node of binary tree

    public BTNode createTree(){
        BTNode A = new BTNode('A');
        BTNode B = new BTNode('B');
        BTNode C = new BTNode('C');
        BTNode D = new BTNode('D');
        BTNode E = new BTNode('E');
        BTNode F = new BTNode('F');
        BTNode G = new BTNode('G');
        BTNode H = new BTNode('H');

        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        E.right = H;
        return A;
    }
}

Test:

public class Test {
    public static void main(String[] args) {
        BinaryTree binaryTree = new BinaryTree();
        BTNode root =  binaryTree.createTree();
        System.out.println("asdasdfadf");
    }
}

Commissioning results:

As you can see, we have created a binary tree.

Again, the above code is not a way to create a binary tree. In the future, I will write a blog again to explain the key points.

3.6. Ergodic binary tree

Traversal is to search each node in the tree in turn along a certain search route
Each point is visited once and only once. The operation of the access node depends on the specific application problem (for example, print the node content and add 1 to the node content). Traversal is one of the most important operations on binary tree and the basis of other operations on binary tree.

Binary trees can be traversed in many ways. If we limit the habitual way from left to right, there are four main ways:

  1. Preorder traversal
  2. Middle order traversal
  3. Postorder traversal
  4. level traversal

Next, let's explain various traversals.

3.6.1. Preorder traversal

If the binary tree is empty, the empty operation returns. Otherwise, first visit the root node, then traverse the left subtree in the previous order, and then traverse the right subtree in the previous order. (left and right roots) as shown in the figure below, the traversal order is: ABDGHCEIF.

//Preorder traversal
void preOrder(BTNode root){
        if(root == null){
            return;
        }
        System.out.print(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

3.6.2. Middle order traversal

If the tree is empty, the empty operation returns. Otherwise, start from the root node (note that the root node is not accessed first), traverse the left subtree of the root node in middle order, then access the root node, and finally traverse the right subtree in middle order (left root right). As shown in the following figure, the traversal order is GDHBAEICF.

//Middle order traversal
    void inOrder(BTNode root){
        if(root == null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

3.6.3. Postorder traversal

If the tree is empty, the empty operation returns. Otherwise, traverse and access the left and right subtrees from left to right, first leaves and then nodes, and finally access the root node (left and right roots). As shown in the figure below, the traversal order is GHDBIEFCA.

//Postorder traversal
    void postOrder(BTNode root){
        if(root == null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val+" ");
    }

3.6.4. level traversal

If the tree is empty, the empty operation returns. Otherwise, access is started from the first layer of the tree, that is, the root node, and traversed layer by layer from top to bottom. In the same layer, access the nodes one by one from left to right. As shown in the following figure, the traversal order is ABCDEFGHI.

3.7. Basic operation of binary tree

 // Find the number of root nodes of the whole tree
    int size(BTNode root){
        if(root == null){
            return 0;
        }
        return size(root.left) + size(root.right) + 1;
    }


    // Get the number of leaf nodes
    int getLeafNodeCount(BTNode root){
        if(root == null){
            return 0;
        }
        if(root.left == null && root.right == null){
            return 1;
        }else{
            return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
        }
    }
    /**
     * Get the number of layer K nodes
     * Sub question ideas:
     *
     */
    int getKLevelNodeCount(BTNode root,int k) {
        if(root == null || k <= 0) {
            return 0;
        }
        if(k == 1) {
            return 1;
        }
        return getKLevelNodeCount(root.left,k-1) + getKLevelNodeCount(root.right,k-1);
    }

    /**
     * Gets the height of the binary tree
     * Time complexity: O(n)
     * Space complexity: O()
     */
    int getHeight(BTNode root) {
        if(root == null) return 0;
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return leftHeight > rightHeight ? leftHeight+1 : rightHeight+1;
    }

    int getHeight2(BTNode root) {
        if(root == null) return 0;
        return getHeight2(root.left) > getHeight2(root.right) ?
                getHeight2(root.left)+1 : getHeight2(root.right)+1;
    }

    /**
     * Detect whether the element with value exists
     */
    BTNode find(BTNode root, char val) {
        if(root == null) return null;
        if(root.val == val) return root;

        BTNode ret = find(root.left,val);
        if(ret != null) {
            return ret;
        }
        ret = find(root.right,val);
        if(ret != null) {
            return ret;
        }
        return null;
    }

    /**
     * Is it a complete binary tree
     * @param root
     * @return
     */
    boolean isCompleteTree(BTNode root) {
        if(root == null) return true;
        Queue<BTNode> queue = new LinkedList<>( );
        queue.offer(root);
        while (!queue.isEmpty()) {
            BTNode cur = queue.poll();
            if(cur != null) {
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }

        while (!queue.isEmpty()) {
            BTNode top = queue.peek();
            if(top != null) {
                return false;
            }
            queue.poll();
        }
        return true;
    }

summary

It took one day to complete. If there are omissions, please forgive me. I hope you can click three times to support me. Thank you!

Topics: Java Algorithm data structure