Non-recursive method of binary tree traversal

I believe everyone is very familiar with the recursive method of binary tree traversal, in fact, it is a similar framework

if(p!=null){
    
    
	//前序遍历时访问结点
	if(p.left!=null){
    
    
		//递归进入左子节点遍历
	}
	//中序遍历时访问结点
	if(p.right!=null){
    
    
		//递归进入右子节点遍历
	}
	//后序遍历时访问结点
}

It can be seen that the recursive method of traversing the pre-middle-post order is very simple, but this method is not very meaningful for us to learn programming, but the iterative method can reflect a person's thinking ability, especially in the interview , Then how to write the code of the non-recursive method of traversing the binary tree in the first, middle and last order?

The front-middle-post-order traversal framework of binary tree

The front-middle-post-order traversal also has their corresponding frameworks: their core code is as follows: (from Leetcode Guo Guo)
Pre-order core code

  while(root != null || !stack.isEmpty()){
    
    
    //go left down to the ground
    while(root != null){
    
    
      res.add(root.val);
      stack.push(root);
      root = root.left;
    }

    //if we reach to the leaf, go back to the parent right, and repeat the go left down.
    TreeNode cur = stack.pop();
    root = cur.right;
  }

Intermediate core code

while (root != null || !stack.isEmpty()) {
    
    
    while (root != null) {
    
    
        stack.push(root);
        root = root.left;
    }
    root = stack.pop();
    res.add(root.val);
    root = root.right;
}

After the core code

while(root != null || !stack.isEmpty()){
    
    
    while(root != null){
    
    
        res.add(root.val);
        stack.push(root);
        root = root.right;
    }

    TreeNode cur = stack.pop();
  	root = cur.left;
}

Preorder traversal of binary tree

Corresponding to leetcode144 questions

Problem Description

Give you the root node root of the binary tree, and return the pre-order traversal of its node value.
Example 1:
Insert picture description here
Input: root = [1,null,2,3]
Output: [1,2,3]
Example 2:

输入:root = []
输出:[]

Example 3:

输入:root = [1]
输出:[1]

Example 4:
Insert picture description here

输入:root = [1,2]
输出:[1,2]

Problem-solving ideas:

The order of preorder traversal is the root left and right
. The framework of preorder traversal is as follows:

  while(root != null || !stack.isEmpty()){
    
    
    //go left down to the ground
    while(root != null){
    
    
      res.add(root.val);
      stack.push(root);
      root = root.left;
    }

    //if we reach to the leaf, go back to the parent right, and repeat the go left down.
    TreeNode cur = stack.pop();
    root = cur.right;
  }

Insert picture description here
For pre-order traversal, we first get the root node, and then go to the left. In the framework, we first visit the corresponding node value, then push the node into the stack, and go to the left, that is, point to its right child node. When the while loop ends, it is found that the left is empty, and then an element is popped from the stack and goes to its right child node. Since the right child node of 3 is empty at the beginning, it can be ignored, and then the next outer loop At the time, because root is empty, without going through the inner while loop, element 2 is popped from the stack, and then the right child node of 2 is accessed. Enter 4, and then continue to the left of 4, we can see that during the pre-order traversal, we always go down to the left as much as possible. When we reach the bottom left and there is no way to go, we pop up Element, and go to the right of the current node, and then go all the way down to the left . In other words, there is a trend here, that is, I keep going down to the left until there is nowhere to go. At this time, I will pop the stack again to see if there is a way to go on the right. If there is still on the right, then We went to the right, and then immediately went down to the left.

Implementation code

class Solution {
    
    
    List<Integer> list;         //用list集合来保存我们遍历过程中的元素
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        list=new ArrayList<>();
        //创建一个栈,模拟递归时的系统栈
        Stack<TreeNode> stack=new Stack<TreeNode>();
        //当结点不为空并且栈也不为空的时候,就说明还有元素待遍历
        while(root!=null || !stack.empty()){
    
    
            //如果可以一直往左走,就一直往左右,一直走到底
            while(root!=null){
    
    
                list.add(root.val);       //前序遍历先访问根节点
                stack.push(root);         //将结点入栈
                root=root.left;           //一直往走左
            }
            //如果不能再往左走,就弹出一个元素
            root=stack.pop();           //弹出栈顶元素
            //然后先往右走一步
            root=root.right;
        }
        return list;
    }
}

Post-order traversal of binary tree

Problem Description

Given a binary tree, return its post-order traversal.
Example:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,1]

Advanced: The recursive algorithm is very simple, can you do it through an iterative algorithm?

Problem solving ideas

The sequence of
Insert picture description here
post-order traversal is left and right roots. The sequence of post-order traversal is left and right roots. If we reverse the order, it becomes the root right and left. This is the same as the preorder traversal. If we can get the root right and left, this time We can get the left and right roots through the reverse method. What is the difference between the right and left roots and the left and right roots? In the pre-order traversal, we are root=root.left, so here, we are root=root,right, before In the sequence traversal, we are root=root.right, so here, we are root=root,left , and other codes are actually surprisingly similar. If we look at the graph, we are going as far as possible to the right, until we have nowhere to go, we will pop up the element, and consider the left node of this element. But once we get the new node, we will stick to the right again until we have nowhere to go, and then go up.
Finally, we can use the reverse function provided by the Java collection class to reverse the order .

Implementation code

class Solution {
    
    
    private List<Integer> list;
	public List<Integer> postorderTraversal(TreeNode root) {
    
    
		list=new ArrayList<Integer>();
        Stack<TreeNode> stack=new Stack<TreeNode>();
        //后序遍历序列是左右根,我们遵循根右左的规则,它与前序遍历左右刚好相反
        while(root!=null || !stack.empty()){
    
    
            //我们选择一直往右走,直到走到底
            while(root!=null){
    
    
                list.add(root.val);     //根右左,同样是先访问根节点
                stack.push(root);       //入栈
                root=root.right;        //一直往右走
            }
            root=stack.pop();   //弹出一个元素
            //走到底之后,就向左走一步
            root=root.left;
        }
        //上面我们得到了一个根右左的序列,要想得到左右根,转置一下即可。
        Collections.reverse(list);
		return list;
        
    }
}

In-order traversal of binary tree

Problem Description

Given the root node root of a binary tree, return its mid-order traversal.
Example 1:
Insert picture description here

输入:root = [1,null,2,3]
输出:[1,3,2]

Example 2:

输入:root = []
输出:[]

Example 3:

输入:root = [1]
输出:[1]

Example 4:
Insert picture description here

输入:root = [1,null,2]
输出:[1,2]

Problem-solving ideas:

The sequence traversed in the middle order is left root right
Insert picture description here

while (root != null || !stack.isEmpty()) {
    
    
    while (root != null) {
    
    
        stack.push(root);
        root = root.left;
    }
    root = stack.pop();
    res.add(root.val);
    root = root.right;
}

In the pre-order traversal and post-order traversal, we all visit the node during the inner while loop traversal (that is, adding the node value to the container), but the middle-order traversal does not put the value when pushing the stack Into. Because our order is left root right, until we get nowhere, the first element we pop up is put into the result, because the preorder traversal and reverse postorder traversal both visit the root node first, so in The memory has been accessed during the while loop traversal. The process here is that when we go all the way to the left, we go to the point of 3, and then pop up, add 3 to the result set, and then continue to pop up, until there is a right node, go one step to the right, and then again Continue the previous process.

Implementation code

class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        List<Integer> list=new ArrayList<Integer>();
		Stack<TreeNode> stack=new Stack<TreeNode>();       //辅助栈
        while(root!=null || !stack.empty()){
    
    
            //一直往左走,直到走到底,但是我们不将中间拿到的结点值放入到容器中
            while(root!=null){
    
    
                stack.push(root);
                root=root.left;
            }
            //出栈一个结点,并将其放入到容器中
            root=stack.pop();
            list.add(root.val);
            root=root.right;
        }
        return list;
    }
}

to sum up:

For the pre-middle-post-order traversal, their non-recursive traversal code is very similar. What we return is a list set. An important point here is when we add the obtained node value to the container. This is What we need to consider.

Guess you like

Origin blog.csdn.net/qq_39736597/article/details/114009466