skip to content

In iterative depth-first traversal with an explicit stack, why push children in reverse order?

level: middleimportance: should knowfreq 40%

answer

  1. Which child comes back out first
  2. Recursion has one child pending at a time
  3. The iterative loop pushes them all at once
  4. Last in, first out, applied to siblings
  5. Push in the mirror of the visiting order

basics

~20 s

A stack returns the most recent push, so pushing children left to right makes the rightmost child come out first. Pushing them right to left puts the leftmost on top, which reproduces the order recursion visits siblings in.

solid answer

~50 s

Recursion visits siblings in order because each call runs to completion before the next one starts — only one child is ever pending. An explicit stack puts **all** the children on at once, and LIFO then hands them back in the opposite order to the one you pushed. So to match recursive left-to-right preorder you push the children right to left. Two further differences are worth naming. The stack holds *nodes*, whereas recursion holds *frames*, each with a resume point — which is why post-order work (anything you would do after the recursive call returns) needs an extra marker or a second stack in the iterative version. And the space profiles differ: recursion keeps roughly one frame per ancestor, about d entries at depth d, while the explicit stack can hold all pending siblings along the path, on the order of b*d for branching factor b.

code

pseudocode · 8 lines
pseudocode
S = empty stack
push(S, root)
while S is not empty:
    node = pop(S)
    visit(node)
    C = children(node)
    for i in length(C)-1 .. 0:
        push(S, C[i])

go deeper

for a junior

Be ready to trace the loop on a small tree and say which node is visited second when children are pushed left to right. Remember that a stack hands back the most recent push.

for a middle

Explain why recursion preserves sibling order while an eager stack reverses it, and state the fix. Know that swapping the stack for a queue turns the same loop into level-by-level traversal.

for a senior

Demonstrate the consequences: where visit order is load-bearing for rendering or deterministic output, why post-order needs a phase marker or a second stack, and how eager pushing changes peak memory on wide structures.

for a principal

Own the readability-versus-control tradeoff. Argue when a team is better served by the plainly recursive version and when the explicit form is worth its extra state, and how you keep traversal order deterministic across a codebase.

## The claim being tested The common belief is that an explicit stack simply *is* recursion, so swapping one for the other changes nothing observable. It changes two things: the order siblings are visited, and what the pending state can express. Both fall out of the same fact — a stack returns the most recently pushed item. ## Why recursion visits siblings in order Walk a nested outline: a document node with sections, each section with subsections. Recursive preorder visits the node, then recurses into child 1 and does not come back until that entire subtree is finished, then child 2, and so on. At any instant exactly **one** child is in flight; the others have not been touched yet. The order the loop iterates them is the order they are visited, with no reversal anywhere. ## Why the naive iterative version flips them The iterative form pops a node, visits it, and pushes all of its children at once. Now several siblings are pending simultaneously, sitting in one stack, and the next pop returns whichever was pushed **last**. Push children 1, 2, 3 in order and the traversal descends into child 3 first. The subtree order within each child is still depth-first, but siblings come out mirrored, and the mirroring compounds at every level. So you push right to left. Child 3, then 2, then 1 leaves child 1 on top, and the traversal descends into it first — identical to recursion. This is not a hack; it is compensating for the one place the two schemes differ. A fair question is whether it matters. If the traversal only needs to *reach* every node — summing sizes, collecting identifiers into a set — sibling order is irrelevant and you should push in whatever order is cheapest. It matters as soon as the output is ordered: rendering an outline, emitting a document in reading order, producing a deterministic diff, or writing a test that asserts a fixed visit sequence. Non-determinism in traversal order is a real source of flaky snapshot tests. ## Nodes versus frames The deeper difference is what each scheme stores. A recursive call keeps a frame per pending call: the node, the loop position among its children, and a **resume point** — the place execution continues once the child returns. That resume point is what makes post-order work possible for free: any statement written after the recursive call runs when the subtree completes. An explicit stack of bare nodes has no resume point. Once you pop a node and push its children, there is no record that you still owe it a closing action. That is why an iterative post-order traversal needs something extra, and the two standard answers are: - push a pair of (node, state) and re-push it with state advanced, so a node is seen once on the way down and once on the way up; or - keep a second stack, collecting nodes in a reversed order and unwinding it at the end. When an interviewer asks you to emit closing markers as well as opening ones — closing an outline level, emitting a closing tag, aggregating child results into a parent — this is the mechanic being probed. Answering it with a plain node stack is the standard miss. ## Space is not the same either At depth d with branching factor b, recursion keeps about **d** frames: one per ancestor of the current node. The explicit stack keeps every unvisited sibling along that whole path, on the order of **b*d** entries. For a wide, shallow structure the difference is large, and it is one reason a traversal that pushes eagerly can hold far more memory than the recursion it replaced. Pushing lazily — keeping an iterator position rather than all children — brings the profile back toward the recursive one at the cost of more bookkeeping. ## The one-line contrast worth knowing Swap the stack for a queue and the identical loop produces level-by-level order instead of depth-first. Nothing else in the code changes. That is the cleanest demonstration that the container's discipline, not the loop, chooses the traversal order — LIFO drives you deep, FIFO drives you wide. ## What a strong answer sounds like State the mechanism (LIFO hands back the last push, so pushing in order reverses siblings), state the fix (push right to left), then qualify it: order only matters when the output is ordered, the node stack cannot express post-visit work without an extra marker, and the peak memory profiles differ because recursion holds ancestors while the explicit stack holds pending siblings too.

  • When does sibling order in an iterative traversal genuinely not matter?
    When the traversal only has to reach every node and the result is order-independent — counting nodes, summing sizes, collecting identifiers into a set, checking whether a property holds anywhere. Then push in whatever order is cheapest. Order becomes load-bearing as soon as the output is a sequence: rendered text, a serialised document, a deterministic diff, or a test asserting a fixed visit sequence.
  • Why is post-order harder with an explicit stack than with recursion?
    Because a stack of bare nodes records no resume point. Recursion keeps a frame per pending call, so any statement written after the recursive call naturally runs once the subtree finishes. Iteratively you must add that state yourself — push each node with a phase marker and re-push it advanced, or collect into a second stack and unwind it — otherwise there is nothing to tell you a node's children are done.
  • How do the memory profiles of the two forms differ on a wide tree?
    Recursion keeps roughly one frame per ancestor, about d entries at depth d. The eager explicit stack also holds every unvisited sibling along that path, on the order of b*d for branching factor b, so a wide shallow structure can make the iterative version hold far more at peak. Pushing lazily, keeping a child position instead of all children, restores the recursive profile.

saying these in an interview costs you the question

  • Assumes an explicit stack visits nodes in the same order as recursion
  • Cannot say why pushing children in order reverses them
  • Thinks a plain node stack can produce post-order for free
  • Believes the iterative form always uses less memory
  • Confuses depth-first order with level-by-level order

context