Tree Traversals

Trees
avg O(n)

A tree traversal visits every node of a binary tree exactly once. The surprise: there is only one walk - go left, go right, climb back - but three possible moments to actually visit a node: before its children (pre-order), between them (in-order), or after them (post-order). Each moment gives a different superpower: pre-order can copy a tree, in-order reads a search tree in sorted order, post-order can delete a tree safely. Same steps, different timing - and that one choice changes everything.

Watch the sorted output appear

Press play - or drag the timeline and step through it yourself.
Output 1Output 0Step 1 / 22
831016144

A binary search tree: at every node, smaller values live left, bigger live right. In-order visits left subtree, then the node, then right subtree. Watch the output list grow.

visiting now waiting on the stack in the output parent-child link

Complexity

Best
O(n)
Input already in order
Average
O(n)
Normal mixed input
Worst
O(n)
Worst possible input
Space
O(h)
Extra memory used

Photographing a mansion of nested rooms

Imagine exploring a mansion where every room has a left door and a right door leading to more rooms. Your path is fixed: always take the left door first, then the right, then walk back out. The only question is when you photograph each room. Snap it the moment you enter - that is pre-order, and your album shows the mansion top-down, perfect for rebuilding it later. Snap it between the two doors - that is in-order. Snap it on the way out, after both doors are done - that is post-order, and no room is photographed before every room inside it, which is exactly the order you would demolish the place safely.

How it works, step by step

  1. All three traversals share one recursive skeleton: at a node, handle the left subtree, handle the right subtree, and at some moment visit the node itself (print it, process it).

  2. Pre-order visits first, then goes left, then right. The root comes out first, then each subtree's root before its contents - top-down.

  3. In-order goes left, visits, then goes right. On a binary search tree every smaller value is out before the node, every bigger one after - so the output is sorted.

  4. Post-order goes left, goes right, and visits last. A node only comes out after everything below it - children always before parents.

  5. The recursion stack remembers the way back: a node waits on it while its left side finishes. The stack never grows deeper than the tree's height, so extra space is O(h).

  6. Every node is visited exactly once and every edge is walked twice (down and back up), so all three orders take O(n) time.

The code, in JavaScript

One skeleton, three timings. The only difference between the functions is where the `out.push` line sits - and that line decides what the order is good for.

javascript
const node = (value, left = null, right = null) => ({ value, left, right });

// The BST from the animation: insert 8, 3, 10, 1, 6, 14, 4.
const tree = node(8,
  node(3, node(1), node(6, node(4))),
  node(10, null, node(14))
);

// Pre-order: visit BEFORE the children. Root first, top-down.
// The order for COPYING or serializing a tree.
function preOrder(n, out = []) {
  if (!n) return out;
  out.push(n.value);        // visit
  preOrder(n.left, out);
  preOrder(n.right, out);
  return out;
}

// In-order: visit BETWEEN the children.
// On a BST, this is SORTED output.
function inOrder(n, out = []) {
  if (!n) return out;
  inOrder(n.left, out);
  out.push(n.value);        // visit
  inOrder(n.right, out);
  return out;
}

// Post-order: visit AFTER the children. Parents last.
// The order for DELETING a tree safely: children go first.
function postOrder(n, out = []) {
  if (!n) return out;
  postOrder(n.left, out);
  postOrder(n.right, out);
  out.push(n.value);        // visit
  return out;
}

preOrder(tree);   // → [8, 3, 1, 6, 4, 10, 14]  (root first)
inOrder(tree);    // → [1, 3, 4, 6, 8, 10, 14]  (sorted!)
postOrder(tree);  // → [1, 4, 6, 3, 14, 10, 8]  (root last)

Dry run: in-order on the 7-node BST

The same steps the visualizer plays, written as a table. Generated by running the real algorithm - not written by hand.

StepOutputWhat happened
11Start at the root, 8. But in-order says left child first - 8 waits, go down to 3.
21At 3 - again, left child first. 3 joins 8 on the wait stack, go down to 1.
31Output 1 - the smallest value in the whole tree. Output: 1.
423's left subtree is done - NOW output 3. Output: 1, 3.
52At 6 - left child first, as always. 6 waits, go down to 4.
63Output 4 - it lands right between 3 and 6. Output: 1, 3, 4.
746's left subtree is done - NOW output 6. Output: 1, 3, 4, 6.
85Everything smaller than 8 is out - NOW output 8. Output: 1, 3, 4, 6, 8.
96Output 10 - straight after its parent, 8. Output: 1, 3, 4, 6, 8, 10.
107Output 14 - the largest value goes last. Output: 1, 3, 4, 6, 8, 10, 14.

Good choice when…

  • You need a BST's values in sorted order - in-order hands you a sorted list in O(n), no sorting step at all.
  • You are copying or serializing a tree - pre-order lists every parent before its children, so rebuilding is a straight read.
  • You must delete a tree, or compute sizes and heights bottom-up - post-order guarantees children are handled before their parent.
  • Expression trees: in-order prints the formula (`a + b`), post-order gives the evaluation order (reverse Polish notation).

Bad choice when…

  • The tree may be a long chain (sorted insert into a BST does this) - the recursion goes O(n) deep and can blow the call stack; use the iterative version instead.
  • You need the tree row by row - nearest levels first. That is level-order with a queue, not a depth-first walk.
  • You are looking for one value in a BST - traversing all n nodes throws away the BST property; compare and go left or right, O(h), done.

Common mistakes

  • In-order output is sorted only on a binary search tree. On a random binary tree the in-order sequence means nothing. Interviewers love handing you a plain tree and waiting for you to claim it is sorted.
  • Recursion depth is the tree's height, not log n. A degenerate tree - every node with a single child, a linked list in disguise - makes it O(n) deep, and at some ten thousand nodes JavaScript throws 'Maximum call stack size exceeded'.
  • Pre-order is the only order that can rebuild the tree from one flat list - and even then only with null markers (or value bounds, on a BST). An in-order list alone can never rebuild it: many different trees share the same in-order sequence.
  • 'Visit' means *process*, not *pass through*. The walk passes each node up to three times; pre, in and post only name which pass does the work. Mix those two ideas up and all three orders look like the same algorithm.

Tree Traversals vs. its closest relatives

AlgorithmBestAverageWorstSpaceStable
Tree Traversalsthis pageO(n)O(n)O(n)O(h)-
Binary Search TreeO(log n)O(log n)O(n)O(n)-
Level-Order TraversalO(n)O(n)O(n)O(n)-
Depth-First SearchO(V + E)O(V + E)O(V + E)O(V)-