GeeksforGeeks Easy

Pre + Post + Inorder in One Traversal

Pre + Post + Inorder in One Traversal: produce preorder, inorder and postorder lists in a single traversal.

Constraints
  • 1 <= number of nodes <= 10⁵
  • -10⁹ <= node value <= 10⁹
  • All three orders must come from a single pass
treestacktraversal
Open on GeeksforGeeks ↗
02

Intuition

The all traversals in one problem asks for preorder, inorder and postorder lists produced by a single traversal instead of three separate ones. The observation that makes it possible: during a depth-first walk, every node is passed through exactly three times, and each visit corresponds to one of the traversal orders: - On arrival, before descending — that is preorder. - Between finishing the left subtree and starting the right — that is inorder. - After both subtrees are complete — that is postorder. A recursive implementation makes this obvious: place three append statements at those three points in the function and all three lists build simultaneously. Doing it iteratively is the interesting version, because the stack must remember which of the three visits a node is on. Push pairs of (node, state) where state runs 1 to 3. Popping a node records it in the list matching its state, then re-pushes it with the state incremented before pushing the next child. The re-push is the mechanism. A node pushed back with state 2 sits underneath its left child on the stack, so it resurfaces only after that entire left subtree has been processed — which is precisely when inorder wants it. The same trick delivers state 3 after the right subtree finishes.

How to spot this pattern

One stack carrying (node, state) pairs simulates the three points a recursive call passes through each node: before the left call, between the calls, and after the right call. Emitting at state 1, 2, 3 gives pre post inorder in one traversal — all three orders from a single pass — this is literally what the call stack does, made explicit.

03

Approach

Try it first

Before reading on: price up what the direct approach costs here, then ask what each node needs from its children before it can answer. Aim for O(n) time and O(h) space.

1

See the three visits per node

A DFS touches each node on arrival, between its two subtrees, and on departure. Those three moments are exactly preorder, inorder and postorder, so one traversal can feed all three lists rather than repeating the walk.

2

Push (node, state) pairs

The stack holds a node together with a counter from 1 to 3 recording which visit is next. Without the state, a popped node gives no way to tell whether its subtrees have been handled.

3

State 1: record preorder, go left

Append the value to the preorder list, re-push the node with state 2, then push its left child. The node now sits beneath its left subtree and will not resurface until that subtree is finished.

4

State 2: record inorder, go right

Append to the inorder list, re-push with state 3, then push the right child. The re-push before the child push is what orders the stack correctly — reversing those two lines produces the wrong sequence.

5

State 3: record postorder and discard

Both subtrees are complete, so append to the postorder list and do not re-push. The node is finished and the stack moves on to whatever was beneath it.

6

Cost of the single pass

Each node is pushed and popped exactly three times, so the work is O(n) with a constant factor of three — still one pass rather than three separate O(n) traversals. Space is O(h) for the stack.

04

Solution & live demo

▶1def all_traversals(root):
▶2 pre, ino, post = [], [], []
▶3 if not root:
▶4 return pre, ino, post
▶5 stack = [(root, 1)]
▶6 while stack:
▶7 node, state = stack.pop()
▶8 if state == 1:
▶9 pre.append(node.val)
▶10 stack.append((node, 2))
▶11 if node.left:
▶12 stack.append((node.left, 1))
▶13 elif state == 2:
▶14 ino.append(node.val)
▶15 stack.append((node, 3))
▶16 if node.right:
▶17 stack.append((node.right, 1))
▶18 else:
▶19 post.append(node.val)
▶20 return pre, ino, post
05

Common pitfalls

Not re-pushing the node with its next state

✗ Wrong
if state == 1:
    pre.append(node.val)
    if node.left: stack.append((node.left, 1))
✓ Right
if state == 1:
    pre.append(node.val)
    stack.append((node, 2))
    if node.left: stack.append((node.left, 1))

The node must be revisited twice more, once after the left subtree and once after the right. Dropping the re-push means inorder and postorder never receive it.

Pushing the child before the node's next state

✗ Wrong
stack.append((node.left, 1))
stack.append((node, 2))
✓ Right
stack.append((node, 2))
if node.left: stack.append((node.left, 1))

A stack pops in reverse, so the child must be pushed last to be processed first. Reversing the order visits the node's state-2 step before its left subtree, scrambling the inorder output.

Running three separate traversals

✗ Wrong
return preorder(root), inorder(root), postorder(root)
✓ Right
stack = [(root, 1)]

Three passes is three times the tree walking, and the point of the exercise is seeing that all three orders are the same walk sampled at different moments. One pass makes that relationship visible.

06

Edge cases

Skewed tree

Stack depth reaches n — same as recursion would.

Empty tree

All three lists empty.

07

Complexity

Time
O(n)
Space
O(h)
Three visits per node, one stack.