3.4.2Trees

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

2,152 words10 min readdifficulty · medium6 backlinks

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 subtree

WHY 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:

  1. N — process (visit) the current Node.
  2. L — recurse into the Left subtree.
  3. 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
Figure — Binary tree — structure, traversals -  preorder, inorder, postorder (recursive and iterative)

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)           # N

Why 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 out

Why 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 out

Why 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 = postorder

Why does reversing work? N R L reversed is L R N, which is exactly postorder. Slick.


Complexity (derive it)

  • Time = O(n)O(n) for all traversals: each of the nn nodes is visited (pushed/popped) a constant number of times.
  • Space = O(h)O(h) where hh = tree height (the stack/recursion depth).
    • Balanced tree: hlog2nh \approx \log_2 nO(logn)O(\log n).
    • Skewed (linked-list-like) tree: h=nh = nO(n)O(n).

Why O(h)O(h) not O(n)O(n) 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?
Preorder = Node-Left-Right; Inorder = Left-Node-Right; Postorder = Left-Right-Node.
In iterative preorder, why push the right child before the left?
A stack is LIFO; pushing right first lets the left child pop (and be processed) first, giving N-L-R order.
Inorder traversal of which special tree gives sorted output?
A Binary Search Tree (BST) — not any binary tree.
Time and space complexity of a tree traversal on n nodes, height h?
Time O(n); Space O(h) (O(log n) balanced, O(n) skewed).
What is the base case that terminates traversal recursion?
When the node is None (empty subtree) → return immediately.
Two-stack iterative postorder works by doing what?
Build order Root-Right-Left into a second stack, then reverse it to get Left-Right-Node.
Given preorder 1 2 4 5 3 and inorder 4 2 5 1 3, which node is the root?
1 (the first element of preorder is always the root).
Why is traversal space O(h) and not O(n)?
The stack only holds the ancestor chain from root to the current node — at most one node per level.

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 O(h)O(h) space.
  • Level-order Traversal (BFS) — the queue-based cousin of these DFS orders.
  • Construct Tree from Preorder + Inorder — application of traversal uniqueness.

Concept Map

has one

each node has

leftchild

rightchild

base case

enables

visited by

N before L R

L then N then R

L R then N

N position rule

implements

Binary Tree

Root node

At most 2 children

Left subtree

Right subtree

Empty tree null

Recursion terminates

Traversal - visit N,L,R

Preorder

Inorder

Postorder

Prefix/Infix/Postfix

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.

Go deeper — visual, from zero

Test yourself — Trees

Connections