Exercises — Binary tree — structure, traversals - preorder, inorder, postorder (recursive and iterative)
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 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→2→4 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. Visit2. →[1,2] - Go left into
4. Visit4.4has no children. →[1,2,4] - Back to
2, go right into5. Visit5. Leaf. →[1,2,4,5] - Left subtree of
1done. Go right into3. Visit3. →[1,2,4,5,3] 3has a right child6. Visit6. 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 to2, keep diving left to4.4has no left child → visit4. →[4] 4has no right child. Back up to2. Its left is done → visit2. →[4,2]- Go right of
2into5. No left child → visit5. →[4,2,5] - Left subtree of
1fully done → visit1. →[4,2,5,1] - Right of
1is3.3has no left child → visit3. →[4,2,5,1,3] - Right of
3is6→ visit6. →[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
2done →2→[4,5,2]. - Right subtree of
1: dive to3.3has no left, right is6. Visit6first →[4,5,2,6]. - Both children of
3done →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 right3, then left2.stack = [3, 2](top is2).
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. So1, then into2:2, then3, then4→1 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 to4(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 isA. - 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 inorderD | B | E→ left childD, right childE. - Right subtree's preorder =
C F. Root =C. Its inorderC F→Chas no left (nothing beforeC), right childF.
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 N — postorder. 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
1→1. Back to3→3. Right of3is6→6. →[1,3,6] - Root
8→[1,3,6,8]. - Right subtree of
8:10has no left →10, then right14→14. →[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 cntThe 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 ofY)+(reverse ofX).
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, then3, then2, then1. Nowcur = Noneandstack = [4, 3, 2, 1]with1on 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.rightisNone, so loop pops again. - Pop
2, visit →[1,2]; rightNone. Pop3→[1,2,3]. Pop4→[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, left3,2, right8,7,9→5 3 2 8 7 9. - Inorder
L N R: leftmost2, then3, back to5, then right subtree inorder7 8 9→2 3 5 7 8 9. - Postorder
L R N:2then3(its only child done); right subtree7 9 8; root5last →2 3 7 9 8 5. - Level-order Traversal (BFS) (queue, level by level):
5|3 8|2 7 9→5 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.)