Binary tree — structure, traversals - preorder, inorder, postorder (recursive and iterative)
WHAT is a binary tree?
class Node:
def __init__(self, val):
self.val = val
self.left = None # left subtree (a Node or None)
self.right = None # right subtreeWHY two children? "Binary" = base-2 branching. This restriction is what lets us reason cleanly: at every node there are exactly two recursive sub-problems (left subtree, right subtree), each itself a binary tree. This self-similarity is why recursion fits trees like a glove.
The ONE idea behind all three traversals
A traversal visits every node exactly once. For each node you do 3 jobs:
- N — process (visit) the current Node.
- L — recurse into the Left subtree.
- R — recurse into the Right subtree.
L always comes before R. The only difference is where N sits:
| Traversal | Order | "Visit node…" |
|---|---|---|
| Preorder | N L R | before children |
| Inorder | L N R | between children |
| Postorder | L R N | after children |

Recursive traversals (derive from first principles)
The recursion is the definition. "To traverse a tree = visit root + traverse left + traverse right", reorder the three lines:
def preorder(node, out):
if node is None: return # base case: empty tree → nothing
out.append(node.val) # N
preorder(node.left, out) # L
preorder(node.right, out) # R
def inorder(node, out):
if node is None: return
inorder(node.left, out) # L
out.append(node.val) # N
inorder(node.right, out) # R
def postorder(node, out):
if node is None: return
postorder(node.left, out) # L
postorder(node.right, out) # R
out.append(node.val) # NWhy the if node is None: return? It is the empty tree base case. Without it the recursion never stops and you crash on None.left.
Iterative traversals (the WHY: recursion = a stack)
Iterative Preorder
Idea: pop a node, visit it, push right first then left (so left pops first — we want N L R).
def preorder_iter(root):
if root is None: return []
out, stack = [], [root]
while stack:
node = stack.pop()
out.append(node.val) # N — visit on pop
if node.right: stack.append(node.right) # push R first…
if node.left: stack.append(node.left) # …so L pops first
return outWhy push right before left? Stack reverses order. To process left before right we must push left last (on top).
Iterative Inorder
Idea: go as far left as possible pushing nodes, then pop (visit), then turn right.
def inorder_iter(root):
out, stack, cur = [], [], root
while cur or stack:
while cur: # 1) dive left, stacking ancestors
stack.append(cur)
cur = cur.left
cur = stack.pop() # 2) leftmost unvisited node
out.append(cur.val) # N — visit between L and R
cur = cur.right # 3) now handle its right subtree
return outWhy dive left first? Inorder needs the left subtree fully done before the node, so we stash ancestors and only visit on the way back up.
Iterative Postorder (two-stack trick — easiest to remember)
Idea: Postorder is reverse of "Root Right Left". Do a preorder-like pass but push left before right, collect into a second stack, then reverse.
def postorder_iter(root):
if root is None: return []
s1, s2 = [root], []
while s1:
node = s1.pop()
s2.append(node.val) # building Root,Right,Left order
if node.left: s1.append(node.left)
if node.right: s1.append(node.right)
return s2[::-1] # reverse → Left,Right,Root = postorderWhy does reversing work? N R L reversed is L R N, which is exactly postorder. Slick.
Complexity (derive it)
- Time = for all traversals: each of the nodes is visited (pushed/popped) a constant number of times.
- Space = where = tree height (the stack/recursion depth).
- Balanced tree: → .
- Skewed (linked-list-like) tree: → .
Why not space? At any moment the stack holds only the chain of ancestors from root to the current node — at most one per level.
Recall Feynman: explain to a 12-year-old
Imagine a family tree where each parent has up to 2 kids. You want to greet everyone in the family without missing anyone. You always greet the left kid's whole family before the right kid's.
- Preorder: greet the parent FIRST, then go meet the kids.
- Inorder: meet ALL of the left kid's family, THEN greet the parent, THEN the right kid's.
- Postorder: meet both kids' families completely, and greet the parent LAST. The "stack" is just remembering which parents you still have to come back to greet — like leaving sticky notes as you walk deeper into the house.
Flashcards
What are the three children-relative positions of the node in pre/in/post-order?
In iterative preorder, why push the right child before the left?
Inorder traversal of which special tree gives sorted output?
Time and space complexity of a tree traversal on n nodes, height h?
What is the base case that terminates traversal recursion?
Two-stack iterative postorder works by doing what?
Given preorder 1 2 4 5 3 and inorder 4 2 5 1 3, which node is the root?
Why is traversal space O(h) and not O(n)?
Connections
- Binary Search Tree — inorder gives sorted order here.
- Recursion and the Call Stack — explains why DFS ⇔ stack.
- Stack (LIFO) — the engine of iterative traversals.
- Tree Height and Balance — drives the space.
- Level-order Traversal (BFS) — the queue-based cousin of these DFS orders.
- Construct Tree from Preorder + Inorder — application of traversal uniqueness.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Binary tree samajhna simple hai: har node ek box hai jisme ek value hoti hai aur uske zyada se zyada do bachche (left aur right). Pura tree khud ke jaise chhote trees se bana hota hai — isi self-similarity ki wajah se recursion yahan perfectly fit hoti hai. Har node par humein teen kaam karne hote hain: node ko visit/print karo (N), left subtree me jao (L), aur right subtree me jao (R). L hamesha R se pehle.
Teeno traversal me sirf ek hi farak hai — N ko kahan rakhte ho. Preorder me node pehle (N L R), Inorder me beech me (L N R), Postorder me sabse last (L R N). Bas yahi yaad rakho: Pre/In/Post batata hai ki root (Node) kahan aayega. Inorder ka ek special use: agar tree ek BST ho, to inorder sorted order deta hai — par yeh sirf BST ke liye sach hai, har tree ke liye nahi.
Iterative version me hum recursion ki jagah apna khud ka stack use karte hain, kyunki recursion andar-andar bhi ek call stack hi use kar rahi hoti hai. Stack LIFO hota hai (last-in-first-out), isliye preorder me hum right ko pehle push karte hain taaki left upar aaye aur pehle process ho. Postorder ke liye two-stack trick sabse easy hai: Root-Right-Left banao aur ulta kar do — ban gaya Left-Right-Node.
Complexity: time hamesha O(n) (har node ek baar visit hota hai), aur space O(h) jahan h tree ki height hai — balanced tree me O(log n), skewed (line jaisa) tree me O(n). Galti se bachna: recursion me if node is None: return mat bhoolna, warna leaf ke None children pe crash ho jaaoge.