Binary Tree Postorder Traversal in Python

Binary tree postorder traversal visits nodes in the order: left subtree, right subtree, then root. This article demonstrates an iterative approach using a stack with node-state pairs to achieve postorder traversal without recursion.

-10 9 10 15 7 Postorder: 9 ? 15 ? 7 ? 10 ? -10

Algorithm Steps

The iterative postorder traversal uses a stack to simulate the recursive calls ?

  • If root is null, return empty array

  • Create a stack with pairs [node, visited_flag]

  • While stack is not empty:

    • Pop node from stack

    • If visited_flag is 0 (first visit):

      • Push [current, 1] back to stack

      • Push right child if exists

      • Push left child if exists

    • If visited_flag is 1 (second visit), add node data to result

Implementation

class TreeNode:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

class Solution:
    def postorderTraversal(self, root):
        if not root:
            return []
        
        result = []
        stack = [[root, 0]]  # [node, visited_flag]
        
        while stack:
            node = stack.pop()
            
            if node[1] == 0:  # First visit
                current = node[0]
                stack.append([current, 1])  # Mark as visited
                
                # Push right first, then left (stack is LIFO)
                if current.right:
                    stack.append([current.right, 0])
                if current.left:
                    stack.append([current.left, 0])
            else:  # Second visit - process node
                result.append(node[0].data)
        
        return result

# Create the binary tree
root = TreeNode(-10)
root.left = TreeNode(9)
root.right = TreeNode(10)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)

# Perform postorder traversal
solution = Solution()
result = solution.postorderTraversal(root)
print("Postorder traversal:", result)
Postorder traversal: [9, 15, 7, 10, -10]

How It Works

The algorithm uses a two-phase approach for each node ?

# Trace through the algorithm step by step
def postorder_with_trace(root):
    if not root:
        return []
    
    result = []
    stack = [[root, 0]]
    step = 1
    
    while stack:
        node = stack.pop()
        print(f"Step {step}: Processing {node[0].data}, visited={node[1]}")
        
        if node[1] == 0:  # First visit
            current = node[0]
            stack.append([current, 1])
            print(f"  Marking {current.data} for later processing")
            
            if current.right:
                stack.append([current.right, 0])
                print(f"  Added right child: {current.right.data}")
            if current.left:
                stack.append([current.left, 0])
                print(f"  Added left child: {current.left.data}")
        else:  # Second visit
            result.append(node[0].data)
            print(f"  Added {node[0].data} to result")
        
        step += 1
        print(f"  Current result: {result}")
        print()
    
    return result

# Example with trace
root = TreeNode(-10)
root.left = TreeNode(9)
root.right = TreeNode(10)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)

print("Tracing postorder traversal:")
final_result = postorder_with_trace(root)
print(f"Final result: {final_result}")
Tracing postorder traversal:
Step 1: Processing -10, visited=0
  Marking -10 for later processing
  Added right child: 10
  Added left child: 9
  Current result: []

Step 2: Processing 9, visited=0
  Marking 9 for later processing
  Current result: []

Step 3: Processing 9, visited=1
  Added 9 to result
  Current result: [9]

Step 4: Processing 10, visited=0
  Marking 10 for later processing
  Added right child: 7
  Added left child: 15
  Current result: [9]

Step 5: Processing 15, visited=0
  Marking 15 for later processing
  Current result: [9]

Step 6: Processing 15, visited=1
  Added 15 to result
  Current result: [9, 15]

Step 7: Processing 7, visited=0
  Marking 7 for later processing
  Current result: [9, 15]

Step 8: Processing 7, visited=1
  Added 7 to result
  Current result: [9, 15, 7]

Step 9: Processing 10, visited=1
  Added 10 to result
  Current result: [9, 15, 7, 10]

Step 10: Processing -10, visited=1
  Added -10 to result
  Current result: [9, 15, 7, 10, -10]

Final result: [9, 15, 7, 10, -10]

Key Points

  • Two-phase processing: Each node is visited twice - first to explore children, second to process

  • Stack order: Right child pushed before left child due to LIFO nature

  • Time complexity: O(n) where n is the number of nodes

  • Space complexity: O(h) where h is the height of the tree

Conclusion

Iterative postorder traversal uses a stack with node-state pairs to achieve left-right-root ordering. The two-phase approach ensures children are processed before their parent, maintaining postorder sequence without recursion.

Updated on: 2026-03-25T08:40:27+05:30

1K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements