Post Order Tree Traversal II in Java (Time Complexity: O(n))


Given a binary tree, return the postorder traversal of its nodes' values.

Example:

Input: [1,null,2,3]
   1
    \
     2
    /
   3

Output: [3,2,1]

Follow up: Recursive solution is trivial, could you do it iteratively?

Understanding the Problem

The core challenge of this problem is to perform a postorder traversal of a binary tree. In postorder traversal, the nodes are recursively visited in this order: left subtree, right subtree, root node. The significance of this traversal is that it is used in various applications such as expression tree evaluations, and it ensures that child nodes are processed before their respective parent nodes.

Potential pitfalls include misunderstanding the traversal order and incorrectly handling null nodes.

Approach

To solve this problem, we can consider both recursive and iterative approaches:

Naive Solution: Recursive Approach

The recursive approach is straightforward and easy to implement. However, it is not optimal in terms of stack space usage, especially for deep trees.

Optimized Solution: Iterative Approach

The iterative approach is more complex but avoids the potential stack overflow issues of the recursive approach. We can use a stack to simulate the recursive call stack.

Iterative Approach Using Two Stacks

1. Use two stacks: one for processing nodes and another for storing the postorder traversal.

2. Push the root node to the first stack.

3. While the first stack is not empty, pop a node, push it to the second stack, and push its left and right children to the first stack.

4. Finally, pop all nodes from the second stack to get the postorder traversal.

Algorithm

Here is a step-by-step breakdown of the iterative algorithm using two stacks:

  1. Initialize two stacks: `stack1` and `stack2`.
  2. Push the root node to `stack1`.
  3. While `stack1` is not empty:
    • Pop a node from `stack1` and push it to `stack2`.
    • Push the left child of the popped node to `stack1` (if it exists).
    • Push the right child of the popped node to `stack1` (if it exists).
  4. Pop all nodes from `stack2` and add their values to the result list.

Code Implementation

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PostOrderTraversal {
    // Definition for a binary tree node.
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }

    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;

        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.push(root);

        while (!stack1.isEmpty()) {
            TreeNode node = stack1.pop();
            stack2.push(node);
            if (node.left != null) stack1.push(node.left);
            if (node.right != null) stack1.push(node.right);
        }

        while (!stack2.isEmpty()) {
            result.add(stack2.pop().val);
        }

        return result;
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.right = new TreeNode(2);
        root.right.left = new TreeNode(3);

        PostOrderTraversal solution = new PostOrderTraversal();
        List<Integer> result = solution.postorderTraversal(root);
        System.out.println(result); // Output: [3, 2, 1]
    }
}

Complexity Analysis

The time complexity of the iterative approach is O(n), where n is the number of nodes in the tree. This is because each node is processed exactly once. The space complexity is also O(n) due to the use of two stacks.

Edge Cases

Potential edge cases include:

Each of these cases is handled by the algorithm as it checks for null nodes and processes all nodes in the tree.

Testing

To test the solution comprehensively, consider the following test cases:

Use a testing framework like JUnit to automate these tests.

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

Conclusion

Postorder traversal is a fundamental tree traversal technique with various applications. Understanding both recursive and iterative approaches is crucial for solving related problems efficiently. Practice and explore further to master these concepts.

Additional Resources

For further reading and practice, consider the following resources: