Several ways of traversing the first, middle and last order of Java ~ binary tree (recursive method, iterative method, marking method, etc.) are clear and easy to understand, including complete code

catalogue

I Definition of nodes

II Traversing binary tree by recursive method

Preorder traversal

Medium order traversal

Postorder traversal

III Iterative (non recursive) traversal of binary trees

(1). Iterative simulation method

Preorder traversal

Medium order traversal

Postorder traversal

(2). Null pointer notation

Preorder traversal

Medium order traversal

Postorder traversal

(3). Some simple methods of dispersing

Preorder traversal

Postorder traversal

I Definition of nodes

Firstly, the definition of nodes is given here. This is how the topics related to leetcode tree define nodes

class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode() {}
      TreeNode(int val) { this.val = val; }
      TreeNode(int val, TreeNode left, TreeNode right) {
         this.val = val;
          this.left = left;
          this.right = right;
      }
  }

II Traversing binary tree by recursive method

Preorder traversal

Traverse the binary tree, store the preamble sequence of the binary tree in the list, and benchmark leetcode questions 144, 94 and 145

class Solution {
    List<Integer> list = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root != null){
            list.add(root.val);  //Here is the operation on the node
            preorderTraversal(root.left);
            preorderTraversal(root.right);
        }
        return list;
    }
}

Medium order traversal

class Solution {
    List<Integer> list = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root != null){
            preorderTraversal(root.left);
            list.add(root.val);  //Here is the operation on the node
            preorderTraversal(root.right);
        }
        return list;
    }
}

Postorder traversal

class Solution {
    List<Integer> list = new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root != null){
            preorderTraversal(root.left);
            preorderTraversal(root.right);
            list.add(root.val);  //Here is the operation on the node
        }
        return list;
    }
}

III Iterative (non recursive) traversal of binary trees

(1). Iterative simulation method

The iterative simulation method of preorder and middle order is relatively simple, which is equivalent to walking the whole binary tree in order. Similar to the following figure, preorder traversal is output when the node is accessed for the first time, and middle order traversal is output when the node is accessed for the second time.

Note that the stack is used here. The node is defined outside, and the root node does not need to push into the stack first, then the loop exit condition, and a node should be added= null, which is different from sequence traversal.

Preorder traversal

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null){
            return null;
        }

        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode node = root;
        while(!stack.isEmpty() || node != null) {
            while (node != null) {
                stack.push(node);
                list.add(node.val);
                node = node.left;
            }
            node = stack.pop();
            node = node.right;  //In this step, the stack is empty, but the node is not empty
        }
        return list;
    }
}

Medium order traversal

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null){
            return list;
        }
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode node = root;
        while(!stack.isEmpty() || node != null){
            while (node != null){
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            list.add(node.val);
            node = node.right;
        }
        return list;
    }
}

Postorder traversal

Post order traversal is a little more complex than pre order and middle order. When a node pop comes out, it is necessary to judge which side it traverses from at that time.

If the right subtree is empty or the right subtree has been traversed before, it comes up from the right. Saving the current node as prev means that the traversal has been completed, and then empty the current node to terminate the traversal of the current node.

If the right subtree is not empty and has not been traversed, it comes up from the left and goes to the right. Here, the current node must be push ed in again, because the current node will be accessed again later.

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode node = root;
        TreeNode prev = null;
        while (node != null || !stack.isEmpty()) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            if (node.right == null || node.right == prev) {
                //If the right subtree is empty or the right subtree has been traversed before, it comes up from the right. Saving the current node as prev means that the traversal has been completed
                //Then empty the current node and terminate the traversal of the current node
                res.add(node.val);
                prev = node;
                node = null;
            } else {  //If the right subtree is not empty and has not been traversed, it comes up from the left and goes to the right
                stack.push(node);  //Here, the current node must be push ed in again, because the current node will be accessed again later
                node = node.right;
            }
        }
        return res;
    }
}

(2). Null pointer notation

This null pointer marking method is more general and simple. Simply put, it is to mark with a null pointer so that you can access a node many times, and then do some operations when accessing the node the second time.

Note:

  1. Stack is used here, not queue. Therefore, when entering the stack, you should first enter the right subtree and then the left subtree. So it simulates the execution of the stack.
  2. peek is used to get the node. First judge whether the node is null or not. You can't pop it out directly. If it is a null node, it means that you need to pop out the current node. Pop out the empty node first, then get the element, and finally pop.
  3. Note that this is a stack, first in and then out. If it is a preamble, first enter the right subtree, then the left subtree, and finally the root node. In this way, when it comes out of the stack, it is about the root, that is, the corresponding preamble sequence.

Preorder traversal

class Solution {
    
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // Pop up the node to avoid repeated operations. Next, add the right, middle and left nodes to the stack
                if (node.right!=null) st.push(node.right);  // Add the right node (empty nodes are not stacked)
                if (node.left!=null) st.push(node.left);    // Add left node (empty nodes are not stacked)
                st.push(node);                          // Adding nodes
                st.push(null); // The node in has been accessed but has not been processed. Add an empty node as a tag.
                
            } else { // Only when an empty node is encountered, the next node is put into the result set
                st.pop();           // Pop up empty node
                node = st.peek();    // Retrieve the elements in the stack
                st.pop();
                result.add(node.val); // Add to result set
            }
        }
        return result;
    }
}

Medium order traversal

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
		List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // Pop up the node to avoid repeated operations. Next, add the right, middle and left nodes to the stack
                if (node.right!=null) st.push(node.right);  // Add the right node (empty nodes are not stacked)

                st.push(node);                          // Adding nodes
                st.push(null); // The node in has been accessed but has not been processed. Add an empty node as a tag.

                if (node.left!=null) st.push(node.left);    // Add left node (empty nodes are not stacked)
            } else { // Only when an empty node is encountered, the next node is put into the result set
                st.pop();           // Pop up empty node
                node = st.peek();    // Retrieve the elements in the stack
                st.pop();
                result.add(node.val); // Add to result set
            }
        }
        return result;
    }
}

Postorder traversal

class Solution {

   public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.peek();
            if (node != null) {
                st.pop(); // Pop up the node to avoid repeated operations. Next, add the right, middle and left nodes to the stack
                st.push(node);                          // Adding nodes
                st.push(null); // The node in has been accessed but has not been processed. Add an empty node as a tag.
                if (node.right!=null) st.push(node.right);  // Add the right node (empty nodes are not stacked)
                if (node.left!=null) st.push(node.left);    // Add left node (empty nodes are not stacked)         
                               
            } else { // Only when an empty node is encountered, the next node is put into the result set
                st.pop();           // Pop up empty node
                node = st.peek();    // Retrieve the elements in the stack
                st.pop();
                result.add(node.val); // Add to result set
            }
        }
        return result;
   }
}

(3). Some simple methods of dispersing

Preorder traversal

The marking method of preorder traversal does not need to be so troublesome

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> st = new Stack<>();
        if (root != null) st.push(root);
        while (!st.empty()) {
            TreeNode node = st.pop();
            result.add(node.val);
            if (node.right!=null) st.push(node.right);  // Add the right node (empty nodes are not stacked)
            if (node.left!=null) st.push(node.left);    // Add left node (empty nodes are not stacked)

        }
        return result;
    }
}

Postorder traversal

You can also use set to mark. When you visit a node for the first time, put the right and left subtrees of the node on the stack, and then operate on the node for the second time.

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }
        Deque<TreeNode> stack = new LinkedList<>();
        Set<TreeNode> set = new HashSet<>();

        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(!set.contains(node)){
                set.add(node);
                if (node.right != null){
                    stack.push(node.right);
                }
                if (node.left != null){
                    stack.push(node.left);
                }
            }else {
                res.add(node.val);
                stack.pop();
            }
        }
        return res;
    }
}

Keywords: Java data structure linked list

Added by SystemWisdom on Sun, 09 Jan 2022 05:11:40 +0200