Algorithm review-basic knowledge of binary tree

Various traversals of binary trees

Recursive traversal

Middle-order traversal: The order of middle-order traversal is left root right, and the recursive writing method is relatively simple. Paste the template directly

public void inorder(TreeNode root){
    
    
    if(root == null)	return;
    if(root.left != null) inorder(root.left);
    //当前位置即为操作,可以根据题意进行添加
    if(root.right != null)	inorder(root.right);
}

For example, lettcode94 traverse the binary tree using the in-order traversal method, but need to put back a list, then you can add this part of the logic in the code comment above

public List<Integer> inorderTraversal(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<Integer>();
    inorder(root, res);
    return res;
}
public void inorder(TreeNode root, List<Integer> res){
    
    
    if(root == null)    return;
    if(root.left != null)   inorder(root.left, res);
    res.add(root.val);
    if(root.right != null)  inorder(root.right, res);
}

Then, just cite the other two directly, write out the writing of pre-order traversal and post-order traversal, you only need to place the logic code of the operation in different positions.

//先序遍历
public List<Integer> preorderTraversal(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<Integer>();
    inorder(root, res);
    return res;
}
public void preorder(TreeNode root, List<Integer> res){
    
    
    if(root == null)    return;
    res.add(root.val);
    if(root.left != null)   inorder(root.left, res);
    if(root.right != null)  inorder(root.right, res);
}
//后序遍历
public List<Integer> postorderTraversal(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<Integer>();
    inorder(root, res);
    return res;
}
public void postorder(TreeNode root, List<Integer> res){
    
    
    if(root == null)    return;
    if(root.left != null)   inorder(root.left, res);
    if(root.right != null)  inorder(root.right, res);
    res.add(root.val);
}

Non-recursive traversal

The advantage of recursive traversal is that the code is concise, but when the binary tree has more nodes, it is easy to burst StackOverFlow, so we generally also write the non-recursive writing of the binary tree. Generally speaking, the recursive writing can be changed to the non-recursive writing. , This requires the use of a data structure stack. The stack is characterized by first-in-last-out. For in-order traversal, the left node is traversed first, so all left nodes can be added to the stack first, and then the last left node Take it out to get the value, then take out the right node and repeat

public List<Integer> inorder(TreeNode root){
    
    
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new LinkedList<>();
    while(root != null && !stack.isEmpty()){
    
    
		while(root != null){
    
    
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        res.add(root.val);
        root = root.right;
    }
    return res;
}

With the foundation of the middle-order traversal, you can write it directly by writing the first-order traversal

public List<Integer> perorder(TreeNode root){
    
    
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new LinkedList<>();
    while(root != null || !stack.isEmpty()){
    
    
        while(root != null){
    
    
            res.add(root.val);
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        root = root.right;
    }
    return res;
}

What about post-order traversal? When performing post-order traversal, you need to determine whether the current node has left and right nodes, which is more troublesome. A more flexible method is used here, because the first-order traversal is the left and right roots, and the post-order traversal is the left and right roots. You can change the left and right children of the original binary tree. The tree is reversed, and then the result of the pre-order traversal can be reversed to get the result of the post-order traversal, for example

Original tree:

      1
    /    \
   2      3
  /  \    /  \
 7   6   4	  5

Post-order traversal: 7 6 2 4 5 3 1

Invert left and right nodes

      1
    /    \
   3      2
  /  \   /  \ 
 5    4 6	 7

Pre-order traversal: 1 3 5 4 2 6 7

Reverse the pre-order traversal to get: 7 6 2 4 5 3 1 is the post-order traversal of the original tree, and reversing the left and right subtrees is relatively simple and can be done. You only need to traverse the right subtree first during the preorder traversal, and then Just traverse the left subtree.

public List<Integer> postorder(TreeNode root){
    
    
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> stack = new LinkedList<>();
    while(root != null || !stack.isEmpty()){
    
    
        while(root != null){
    
    
            res.add(root.val);
            stack.push(root);
            root = root.right;
        }
        root = stack.pop();
        root = root.left;
    }
    Collections.reverse(res);
    return res;
}

Level traversal

Hierarchical traversal refers to the order from top to bottom, from left to right, then BFD, breadth-first algorithm can generally be used, and the implementation of this algorithm requires the help of a data structure queue. The advantage of the queue is first-in, first-out.

Why use queues?

    3
   / \
  9  20
    /  \
   15   7

return:

[3,9,20,15,7]

According to the above example, we can know that we need to save each node in order to get the possible left and right subtree nodes of the node. If the printing is from left to right, using the queue first in first out just meets this feature

public int[] levelOrder(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> q = new LinkedList<>();
    if(root == null)    return new int[]{
    
    };
    q.add(root);
    while(!q.isEmpty()){
    
    
        TreeNode temp = q.poll();                
        res.add(temp.val);
        if(temp.left != null) q.add(temp.left);
        if(temp.right != null) q.add(temp.right);
    }
    int[] r = new int[res.size()];
    for(int i = 0;i < res.size();i++){
    
    
        r[i] = res.get(i);
    }
    return r;
}

Here is also a brief review of some common methods of Deque as a stack and queue

作为栈

method effect
push(e) Pop in
pop() pop up
peek() Take the top element of the stack

作为队列

method effect
offer(e) Join to the head of the team
poll() Exclude from the end of the line
peek() From the end of the line

Exercise

Sword refers to offer32 question 1

The binary tree is printed in layers from top to bottom, the nodes in the same layer are printed in order from left to right, and each layer is printed to one line.

例如:
给定二叉树: [3,9,20,null,null,15,7],
	3	
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

Different from the level traversal, this problem also needs to print the data of each layer as a line, which needs to be because the data of each line is stored in the queue, which requires operations on the current queue during each cycle. You can remember the size of the queue first, and then add the child nodes

public List<List<Integer>> levelOrder(TreeNode root) {
    
    
    List<List<Integer>> res = new ArrayList<>();
    Deque<TreeNode> q = new LinkedList<>();

    if(root == null)    return new ArrayList<List<Integer>>();
    q.offer(root);
    while(!q.isEmpty()){
    
    
        List<Integer> tempA = new ArrayList<>();
        //这行代码很重要,需要记住当前层的队列数量
        // for(int i = queue.size(); i > 0; i--)
        int size = q.size();
        for(int i = 0;i < size;i++){
    
    
            TreeNode temp = q.poll();
            if(temp.left != null) q.offer(temp.left);
            if(temp.right != null) q.offer(temp.right);
            tempA.add(temp.val);
        }
        res.add(tempA);
    }
    return res;
}

Sword refers to offer32 question 2

Please implement a function to print the binary tree in zigzag order, that is, the first line is printed from left to right, the second layer is printed from right to left, and the third line is printed from left to right. Others And so on.

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]

This is a variant of the above problem, you only need to invert the data when you encounter even-numbered rows.

public List<List<Integer>> levelOrder(TreeNode root) {
    
    
        List<List<Integer>> res = new ArrayList<>();
        Deque<TreeNode> q = new LinkedList<>();
        if(root == null) return new ArrayList<>();
        int flag = 1;
        q.offer(root);
        while(!q.isEmpty()){
    
    
            List<Integer> temp = new ArrayList<>();
            for(int i = q.size();i >0 ;i--){
    
    
                TreeNode node = q.poll();
                temp.add(node.val);
                if(node.left != null)   q.offer(node.left);
                if(node.right != null)  q.offer(node.right);
            }
            if(flag % 2 == 0){
    
    
                Collections.reverse(temp);
            }
            res.add(temp);
            flag++;
        } 
        return res;
    }

Guess you like

Origin blog.csdn.net/weixin_44706647/article/details/115190793