- Tree structure: tree structure is a data structure that describes nonlinear hierarchical relationships.
-
A tree is a set of n data nodes, which contains a root node. Under the root node, there are some non intersecting subsets, which are subtrees of the root node.
-
Basic characteristics of tree structure:
(1) In a tree structure, there is only one node without a direct precursor, which is the root node of the tree;
(2) Except for the root node, each other node has only one direct precursor;
(3) Each node can have any number of direct successors.
- Concept of tree
- Parent node and child node: the root of each node subtree is called the child node of the node, and accordingly, the node is called the parent node of its child node;
- Sibling node: a node with the same parent node is called a sibling node;
- Node degree: the number of subtrees contained in a node;
- Degree of tree: refers to the largest degree among all nodes of the tree;
- Leaf node: the node with zero in the tree is called leaf node or terminal node;
- Branch node: a node that is not zero in the tree is called a branch node or a non terminal node;
- Number of layers of nodes: the number of layers of nodes is calculated from the root of the tree. The root node is the first layer, followed by the second, third,... n layers (the tree is a hierarchical structure, and each node is at a certain level);
- Depth of tree: the maximum number of layers of nodes in the tree is called the depth of the tree;
- Ordered tree: if the subtree (sibling node) of each node in the tree is arranged from left to right in a certain order, it is called ordered tree;
- Unordered tree: if the subtrees (sibling nodes) of each node in the tree are not arranged in a certain order, it is called unordered tree;
- Forest: a collection of n (n > 0) disjoint trees.
- Binary tree
-
Binary tree is a special form of tree structure. It is a set of n nodes. Each node can have at most two nodes.
-
The subtree of a binary tree is still a binary tree.
-
The two subtrees corresponding to a node of a binary tree are called left subtree and right subtree respectively. Because the subtree of binary tree can be divided into left and right, binary tree is an ordered tree.
-
In the ordinary tree structure, there is no limit on the maximum degree of nodes, while the maximum degree of binary tree nodes is 2.
-
A binary tree structure can also be empty. This spatiotemporal binary tree has no data nodes and is an empty set.
-
There are two special types of binary trees:
(1) Full binary tree: in a binary tree, except for the leaf node of the lowest layer, the node of each layer has two child nodes
(2) Complete binary tree:
In the binary tree, except the last layer, the nodes of other layers reach the maximum number, and the leaf nodes of the last layer exist continuously in the order of left to right, only a few nodes on the right of the last layer are missing.
- Properties of complete binary tree
The focus of tree structure research in binary tree is complete binary tree. For a complete binary tree, if the tree contains n nodes, it is assumed that these nodes are stored in order. Then, for any node m, it has the following properties:
- If m= 1, then the number of the parent node of node m is m/2;
- If 2m ≤ n, the number of the root node of the left subtree of node m is 2m; If 2 * m > N, there is no left subtree and no right subtree
- If 2m+1 ≤ n, the root node number of the right subtree of node m is 2m+1; If 2 * m + 1 > N,
There is no right subtree. In addition, for the complete binary tree, its depth is [log2n]+1.
These basic properties show the characteristics of complete binary tree structure, which is of great significance in the storage mode and operation processing of complete binary tree.
- Traversal binary tree
Traversing the binary tree is to find all nodes in the binary tree one by one. This is the basic operation of the binary tree, because many operations need to traverse the whole binary tree first. Due to the particularity of binary tree structure, many methods can be used to traverse.
Because the binary tree represents a hierarchical structure, first traverse the whole binary tree by layer. For the layer by layer traversal of binary tree, it is generally not possible to use recursive algorithm to write code, but to use a circular queue for processing.
Of course, recursive algorithm can also be used to simplify the traversal algorithm. Generally, the following methods can be used to traverse the whole binary tree:
- First order traversal: first visit the root node, then traverse the left subtree in order, and finally traverse the right subtree in order.
1. First, define a tree node class information, as follows:
package com.dz.demo.algorithm; public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } }
2. Recursive call is relatively simple, as follows:
private static void preOrderRecursive(TreeNode root) { if (root == null) return; System.out.println(root.val); preOrderRecursive(root.left); preOrderRecursive(root.right); }
3. The non recursive method is mainly completed with the help of stack structure:
private static void preOrderUnRecursive(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.empty()) { TreeNode temp = stack.pop(); if (temp == null) continue; System.out.println(temp.val); // Specify the order of the stack in and out, first in and then out, so traverse first and push the right subtree first stack.push(temp.right); stack.push(temp.left); }
- Middle order traversal: first traverse the left subtree in middle order, then access the root node, and finally traverse the right subtree in middle order.
import java.util.Stack; public class Test { public static void main(String[] args) { TreeNode[] node = new TreeNode[10];//Generate a complete binary tree in the form of an array for(int i = 0; i < 10; i++) { node[i] = new TreeNode(i); } for(int i = 0; i < 10; i++) { if(i*2+1 < 10) node[i].left = node[i*2+1]; if(i*2+2 < 10) node[i].right = node[i*2+2]; } midOrderRe(node[0]); System.out.println(); midOrder(node[0]); } public static void midOrderRe(TreeNode biTree) {//Recursive implementation of middle order traversal if(biTree == null) return; else { midOrderRe(biTree.left); System.out.println(biTree.value); midOrderRe(biTree.right); } } public static void midOrder(TreeNode biTree) {//Recursive implementation of middle order traversal cost Stack<TreeNode> stack = new Stack<TreeNode>(); while(biTree != null || !stack.isEmpty()) { while(biTree != null) { stack.push(biTree); biTree = biTree.left; } if(!stack.isEmpty()) { biTree = stack.pop(); System.out.println(biTree.value); biTree = biTree.right; } } } } class TreeNode//Node structure { int value; TreeNode left; TreeNode right; TreeNode(int value) { this.value = value; } }
- Backward traversal: first traverse the left subtree in backward order, then traverse the right subtree in backward order, and finally traverse the root node.
Core idea of the algorithm:
First of all, we need to find out what the non recursive algorithms of first order, middle order and second order have in common: use the stack to save the previous path, so that after accessing the subtree, we can use the information in the stack to go back to the parent node of the current node for the next operation.
The non recursive algorithm of post order traversal is the most complex of the three sequences. The reason is that post order traversal accesses the left and right subtrees first and then the root node. In the non recursive algorithm, when the stack is used to fallback, it does not know whether to fallback from the left subtree to the root node or from the right subtree to the root node. If you fallback from the left subtree to the root node, you should access the right subtree at this time, If you fall back from the right subtree to the root node, you should access the root node at this time. Therefore, compared with the pre sequence and post sequence, you must add information when pressing the stack, so that you can know whether to return from the left subtree or the right subtree when returning the stack, and then decide the next operation.
import java.util.Stack; public class Test { public static void main(String[] args) { TreeNode[] node = new TreeNode[10];//Generate a complete binary tree in the form of an array for(int i = 0; i < 10; i++) { node[i] = new TreeNode(i); } for(int i = 0; i < 10; i++) { if(i*2+1 < 10) node[i].left = node[i*2+1]; if(i*2+2 < 10) node[i].right = node[i*2+2]; } postOrderRe(node[0]); System.out.println("***"); postOrder(node[0]); } public static void postOrderRe(TreeNode biTree) {//Recursive implementation of post order traversal if(biTree == null) return; else { postOrderRe(biTree.left); postOrderRe(biTree.right); System.out.println(biTree.value); } } public static void postOrder(TreeNode biTree) {//Non recursive implementation of post order traversal int left = 1;//Represents the left node in the auxiliary stack int right = 2;//Represents the right node in the auxiliary stack Stack<TreeNode> stack = new Stack<TreeNode>(); Stack<Integer> stack2 = new Stack<Integer>();//The auxiliary stack is used to determine whether the child node is in the left node or the right node when returning to the parent node. while(biTree != null || !stack.empty()) { while(biTree != null) {//Push the node into stack 1 and mark the node as the left node in stack 2 stack.push(biTree); stack2.push(left); biTree = biTree.left; } while(!stack.empty() && stack2.peek() == right) {//If you return to the parent node from the right child node, the task is completed and the top of the two stacks will pop up stack2.pop(); System.out.println(stack.pop().value); } if(!stack.empty() && stack2.peek() == left) {//If the parent node is returned from the left child node, the flag is changed to the right child node stack2.pop(); stack2.push(right); biTree = stack.peek().right; } } } } class TreeNode//Node structure { int value; TreeNode left; TreeNode right; TreeNode(int value) { this.value = value; }