3.4.2 · D4Trees

Exercises — Binary tree — structure, traversals - preorder, inorder, postorder (recursive and iterative)

3,763 words17 min readBack to topic

Two symbols recur on this page; we define them here, in plain words, before any use:

Throughout, we reuse this one reference tree unless a problem says otherwise. Every node is a box holding a value; a left arrow points to the left child, a right arrow to the right child. A missing arrow means that child is None (the empty tree).

Figure — Binary tree — structure, traversals -  preorder, inorder, postorder (recursive and iterative)

Figure s01 (the reference tree). Root 1 (yellow) at the top. Left child 2, right child 3. Node 2 has children 4 (left) and 5 (right); node 3 has a single right child 6. The green nodes 4, 5, 6 are the leaves. Here and (root→24 is two edges). This is the tree meant whenever a problem says "the reference tree" or "figure s01".

Quick vocabulary reminder, all built in the parent note:

  • N = "visit/process the current node" (append its value to the output list).
  • L = "recurse into the Left subtree", R = "recurse into the Right subtree".
  • Preorder = N L R, Inorder = L N R, Postorder = L R N.

Level 1 — Recognition

Goal: read a tree and produce the raw output sequence. No code, just careful walking.

L1.1 — Preorder by hand

State the preorder traversal of the reference tree in figure s01.

Recall Solution

Preorder is N L R: print the node the instant you arrive, then dive fully left, then right.

  • Visit 1 (root). → [1]
  • Go left into subtree rooted at 2. Visit 2. → [1,2]
  • Go left into 4. Visit 4. 4 has no children. → [1,2,4]
  • Back to 2, go right into 5. Visit 5. Leaf. → [1,2,4,5]
  • Left subtree of 1 done. Go right into 3. Visit 3. → [1,2,4,5,3]
  • 3 has a right child 6. Visit 6. Leaf. → [1,2,4,5,3,6]

Answer: 1 2 4 5 3 6.

L1.2 — Inorder by hand

State the inorder traversal of the same tree.

Recall Solution

Inorder is L N R: never print a node until its entire left subtree is finished.

  • From 1, dive left to 2, keep diving left to 4. 4 has no left child → visit 4. → [4]
  • 4 has no right child. Back up to 2. Its left is done → visit 2. → [4,2]
  • Go right of 2 into 5. No left child → visit 5. → [4,2,5]
  • Left subtree of 1 fully done → visit 1. → [4,2,5,1]
  • Right of 1 is 3. 3 has no left child → visit 3. → [4,2,5,1,3]
  • Right of 3 is 6 → visit 6. → [4,2,5,1,3,6]

Answer: 4 2 5 1 3 6.

L1.3 — Postorder by hand

State the postorder traversal.

Recall Solution

Postorder is L R N: a node is printed last, only after both its children's whole families are done.

  • Deepest-left first: 4 (no children) → [4].
  • 5 (no children) → [4,5].
  • Both children of 2 done → 2[4,5,2].
  • Right subtree of 1: dive to 3. 3 has no left, right is 6. Visit 6 first → [4,5,2,6].
  • Both children of 3 done → 3[4,5,2,6,3].
  • Finally the root 1[4,5,2,6,3,1].

Answer: 4 5 2 6 3 1.


Level 2 — Application

Goal: apply the iterative algorithms and the base-case rules to slightly odd inputs.

L2.1 — Iterative preorder push order

Using the reference tree, trace the iterative preorder algorithm (single explicit Stack (LIFO)) and give the stack contents right after visiting node 1.

Recall Solution

Algorithm: pop, visit, then push right first, then left so left pops next.

  • Start: stack = [1].
  • Pop 1, visit → out [1]. Push right 3, then left 2. stack = [3, 2] (top is 2).

Answer: immediately after visiting 1, stack = [3, 2] with 2 on top. Continuing pops 2 next, exactly what preorder wants. Full output: 1 2 4 5 3 6.

L2.2 — Single-node tree

A tree has exactly one node with value 7 and no children. Give all three traversals.

Recall Solution

With no children, L and R both hit the None base case and do nothing. Only N fires.

  • Preorder = N (L,R empty) = 7.
  • Inorder = (L empty) N (R empty) = 7.
  • Postorder = (L,R empty) N = 7.

Answer: all three are 7. Degenerate case: order of N/L/R can't matter when there's only an N.

L2.3 — Empty tree

What does each traversal return on the empty tree (root = None)?

Recall Solution

We must be precise about what is returned. In the list-building traversals used on this page (the ones that build and return an output list, like preorder_iter), the base case is return [] — an empty list, not None. So the traversal of an empty tree is the empty list [], which is the correct, safe answer to append to or iterate over.

(In the recursive void helpers of the parent note, written as def preorder(node, out): if node is None: return, the bare return simply stops that call without appending anything — the accumulated out list stays empty. Same observable result: no values are produced.)

Answer: the traversal yields the empty list [] for all three (never None). This base case is what makes recursion terminate at all — remove it and you crash on None.left.

L2.4 — Right-skewed tree (a linked list in disguise)

Consider the tree where each node has only a right child:

1 -> 2 -> 3 -> 4   (each arrow is a right child)

Give preorder, inorder, and postorder.

Recall Solution

No node has a left child, so every L recursion is empty.

  • Preorder N L R: N then (skip L) then R. So 1, then into 2: 2, then 3, then 41 2 3 4.
  • Inorder L N R: L empty each time, so it's just N then R, same as preorder → 1 2 3 4.
  • Postorder L R N: go all the way right to 4 (deepest), print it, back up printing each → 4 3 2 1.

Answer: Pre = 1 2 3 4, In = 1 2 3 4, Post = 4 3 2 1. Note preorder and inorder coincide here — with no left children there's nothing to sit "before" the node. Using the definitions above, nodes and the longest root-to-leaf path is 1→2→3→4 = three edges, so — the maximally unbalanced ("skewed") shape. See Tree Height and Balance.


Level 3 — Analysis

Goal: reason backwards — from outputs to structure, and about why algorithms behave as they do.

L3.1 — Reconstruct from preorder + inorder

You are told:

  • Preorder = A B D E C F
  • Inorder = D B E A C F

Draw the tree (this is the Construct Tree from Preorder + Inorder technique).

Recall Solution

Key facts. Preorder's first element is always the root. In inorder, everything left of the root is the left subtree, everything right is the right subtree.

  • Preorder starts with A → root is A.
  • In inorder D B E | A | C F: left subtree = {D,B,E}, right subtree = {C,F}.
  • Left subtree's preorder (next 3 items) = B D E. Root of left = B. Its inorder D | B | E → left child D, right child E.
  • Right subtree's preorder = C F. Root = C. Its inorder C FC has no left (nothing before C), right child F.

Resulting tree:

        A
       / \
      B   C
     / \    \
    D   E    F

Check (regenerate): preorder = A B D E C F ✓, inorder = D B E A C F ✓.

L3.2 — Why is space , not ?

Recall = tree height and = number of nodes (both defined at the top of this page). Explain precisely why the recursive/stack space is bounded by the height , not the node count .

Recall Solution

At any single instant during a DFS traversal, the call stack (or explicit Stack (LIFO)) holds only the chain of ancestors from the root down to the node you're currently at — one frame per level. You never hold two siblings' full recursions simultaneously: you finish the left recursion (which pops all its frames) before starting the right. So the maximum stack depth = the longest root-to-node path = the height .

  • Balanced tree: → space .
  • Skewed tree (L2.4): → space .

Answer: space is because only one ancestor chain is live at a time. (See Recursion and the Call Stack.)

L3.3 — Which traversal for "free/delete the whole tree"?

To deallocate a tree safely (free a node only after its children are freed), which traversal must you use, and why?

Recall Solution

You must free children before the parent, otherwise you'd lose the pointers to the children after deleting the parent. That is exactly L R Npostorder. Preorder would free the parent first and orphan the subtrees; inorder frees the right subtree after the parent, same problem.

Answer: Postorder.


Level 4 — Synthesis

Goal: combine ideas, modify algorithms, prove small claims.

L4.1 — Inorder of a BST is sorted

Given the Binary Search Tree below, state its inorder, and explain in one sentence why it comes out sorted.

        8
       / \
      3   10
     / \    \
    1   6    14
Recall Solution

Inorder L N R, diving leftmost first:

  • Leftmost is 11. Back to 33. Right of 3 is 66. → [1,3,6]
  • Root 8[1,3,6,8].
  • Right subtree of 8: 10 has no left → 10, then right 1414. → [1,3,6,8,10,14]

Answer: 1 3 6 8 10 14 — sorted ascending. Why sorted: in a BST, everything in a node's left subtree is smaller and everything in its right subtree is larger. Inorder visits (all-smaller) → node → (all-larger), which is precisely ascending order. This is a BST property, not a property of inorder on arbitrary trees (parent-note mistake #2).

L4.2 — Adapt the two-stack postorder to count leaves

The parent note's two-stack postorder uses stack s1 to drive the walk and stack s2 to collect the N R L order that is reversed at the end. Keep that exact skeleton, but instead of collecting values into s2, count the leaves (nodes with no children). Give the count for the reference tree in figure s01.

Recall Solution

We start from the literal two-stack postorder and change only the "collect" line. In the original, when we pop a node from s1 we append its value to s2; here, at that same moment, we instead test whether the node is a leaf. Because postorder's two-stack pass still visits every node exactly once (that fact is independent of the reversal step), the leaf count is correct.

def count_leaves(root):
    if root is None: return 0
    s1, cnt = [root], 0        # s1 is the SAME driver stack as two-stack postorder
    while s1:
        node = s1.pop()
        # original two-stack line was:  s2.append(node.val)
        # we swap it for the leaf test at the same visit moment:
        if node.left is None and node.right is None:
            cnt += 1
        if node.left:  s1.append(node.left)   # same push order as postorder driver
        if node.right: s1.append(node.right)
    return cnt

The s2 stack (and its final reversal) is simply dropped, because a count doesn't care about the visit order — only that each node is seen once. For s01: nodes 4, 5, 6 have no children → 3 leaves. (1, 2, 3 each have at least one child.)

Answer: 3.

L4.3 — Preorder + Level-order agreement

Under what condition does preorder equal Level-order Traversal (BFS) for the same tree?

Recall Solution

Preorder goes depth-first (dive to a leaf before exploring siblings). Level-order goes breadth-first (finish a whole level before descending). They agree only when "go deep" and "go wide" are the same walk — i.e. when there's never a choice, meaning every level has at most one branching that keeps depth = breadth order.

The cleanest guaranteed case: a right-skewed (or any single-child) chain, like L2.4's 1→2→3→4. Preorder = 1 2 3 4 and level-order = 1 2 3 4. They diverge the instant a node has two children whose subtrees have depth > 1.

Answer: They coincide for a degenerate chain (each node has ≤1 child); in general they differ because preorder is DFS and level-order is BFS.


Level 5 — Mastery

Goal: fully general reasoning, edge cases, and a small proof.

L5.1 — Why does reversing "root, right, left" give postorder?

Prove the two-stack postorder trick from the parent note: doing a modified preorder that pushes left before right (so it processes root, then all-right, then all-left), then reversing the whole list, yields postorder (left-subtree, then right-subtree, then root).

Recall Solution

First, two plain-word definitions so no symbol is unearned:

  • Concatenation of two lists means "write the first list, then the second, end to end." We write it with a plus sign here: [a] + [b, c] means the list [a, b, c].
  • Reversal of a list means "read it back to front": reversing [a, b, c] gives [c, b, a]. A useful rule: reversing a concatenation flips the block order and reverses each block, so reverse of (X + Y) equals (reverse of Y) + (reverse of X).

Let M(x) be the output of the modified pass on the subtree rooted at node x, whose left subtree is Lx and right subtree is Rx. The modified pass visits the root first, then recurses right, then left:

M(x) = [x] + M(Rx) + M(Lx) (root, then all of right, then all of left)

Now reverse both sides, applying the rule above (flip order, reverse each block):

reverse(M(x)) = reverse(M(Lx)) + reverse(M(Rx)) + [x]

Argue by induction (assume it already holds on the smaller subtrees Lx and Rx): if reverse(M(Lx)) equals the true postorder of Lx, and likewise for Rx, then

reverse(M(x)) = postorder(Lx) + postorder(Rx) + [x]

which is exactly the definition of postorder L R N (left subtree, then right subtree, then the node). Base case: an empty subtree gives the empty list both ways, so the claim holds there too. That completes the proof.

Answer: proven — reversing a "root, right, left" walk yields "left, right, root", i.e. postorder.

L5.2 — Iterative inorder on a left-skewed tree

Trace iterative inorder (dive-left / pop / turn-right) on the left-skewed tree:

      4
     /
    3
   /
  2
 /
1

Give the maximum stack depth and the output sequence.

Recall Solution

The algorithm (parent note) does three repeating jobs: (1) dive left pushing every node, (2) pop and visit, (3) turn right. Here every node's right child is None, so step (3) never adds anything new.

  • Dive left: push 4, then 3, then 2, then 1. Now cur = None and stack = [4, 3, 2, 1] with 1 on top. This is the deepest the stack ever gets: max stack depth = 4, which equals and (the full ancestor chain is live at once).
  • Pop/visit/turn-right: pop 1, visit → [1]; 1.right is None, so loop pops again.
  • Pop 2, visit → [1,2]; right None. Pop 3[1,2,3]. Pop 4[1,2,3,4]. Stack empty, done.

Answer: output 1 2 3 4; maximum stack depth 4. This realises the worst-case space for a skewed tree — the concrete illustration of L3.2.

L5.3 — Full traversal battery on a two-child asymmetric tree

For the tree below give all three DFS traversals and the level-order.

        5
       / \
      3   8
     /   / \
    2   7   9
Recall Solution
  • Preorder N L R: 5, left 3,2, right 8,7,95 3 2 8 7 9.
  • Inorder L N R: leftmost 2, then 3, back to 5, then right subtree inorder 7 8 92 3 5 7 8 9.
  • Postorder L R N: 2 then 3 (its only child done); right subtree 7 9 8; root 5 last → 2 3 7 9 8 5.
  • Level-order Traversal (BFS) (queue, level by level): 5 | 3 8 | 2 7 95 3 8 2 7 9.

Answers: Pre = 5 3 2 8 7 9, In = 2 3 5 7 8 9, Post = 2 3 7 9 8 5, Level = 5 3 8 2 7 9. (Notice inorder is sorted — because this happens to be a valid Binary Search Tree.)