7.1 Binary Trees (DFS, BFS & Bottom-Up Recursion)
Learn what a Binary Tree is from scratch, master Preorder/Inorder/Postorder DFS and Level-Order BFS, and solve Height, Diameter, and LCA problems.
1. What Is a Binary Tree?
Up until now, Arrays, Linked Lists, Stacks, and Queues were all 1D lines (each item had at most one next neighbor).
A Binary Tree is a hierarchical data structure (like a family tree or a folder directory on your computer):
- It starts at a single top node called the
root. - Every
TreeNodeholds a value (val) and up to two children:leftandright. - A node with no children (
left == nullandright == null) is called aleaf. - Unlike a Graph, a Tree never has cycles — there is only one unique path from the
rootto any node!
2. Why Do We Need Binary Trees & How Do We Walk Them?
Why Trees Exist
Flat arrays cannot represent nested hierarchies (like HTML DOM elements, organization charts, or decision trees). Trees also divide data into two branches at every level, so a balanced tree of 1,000,000 nodes is only 20 levels tall (log2(1,000,000) ≈ 20)!
The Two Ways to Traverse Every Node (O(N) Time)
- Depth-First Search (DFS — via Recursion): Plunge all the way down to a leaf before backing up.
- Preorder (
Root -> Left -> Right): Visit the parent before its children. - Inorder (
Left -> Root -> Right): Visit left subtree, then parent, then right subtree. - Postorder (
Left -> Right -> Root): Visit both children first, then combine their answers at the parent (Bottom-Up Recursion!).
- Preorder (
- Breadth-First Search (BFS — via a FIFO Queue): Visit the tree floor by floor (Level 0, then Level 1, then Level 2).
Comparison Table: Which Tree Traversal Should You Pick?
| Traversal Order | Visit Sequence | Concrete Example on Tree [Root=4, Left=2, Right=7] | When Interviewers Expect You to Use It |
|---|---|---|---|
| Preorder DFS | Root -> Left -> Right | [4, 2, 7] | Copying/cloning a tree, serializing a tree, or passing top-down bounds from parent to child |
| Inorder DFS | Left -> Root -> Right | [2, 4, 7] (Sorted!) | Binary Search Trees (BSTs) — visits nodes in strictly ascending sorted order |
| Postorder DFS | Left -> Right -> Root | [2, 7, 4] | Bottom-Up Tree DP (Height, Diameter, Balanced Check, Max Path Sum, Lowest Common Ancestor) |
| Level-Order BFS | Floor by floor (Queue) | [[4], [2, 7]] | Right Side View, Zigzag Level Order, Minimum Depth, Level Averages |
Interactive Step-by-Step Trace: DFS Postorder vs. BFS Level-Order
See how bottom-up height calculation and level-by-level queues traverse a Binary Tree:
A parent node cannot know its height until both children report theirs!
3. Basic Operations & Walkthroughs (All 4 Languages)
from collections import deque
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
# 1. Bottom-Up Postorder DFS: Max Depth (Height) of a Binary Tree -> O(N)
def max_depth(root: TreeNode) -> int:
if not root:
return 0
left_h = max_depth(root.left)
right_h = max_depth(root.right)
return 1 + max(left_h, right_h)
# 2. Level-Order BFS (Floor by Floor using a Queue) -> O(N)
def level_order(root: TreeNode) -> list[list[int]]:
if not root:
return []
q = deque([root])
levels = []
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
levels.append(level)
return levels4. Core Interview Patterns
- Diameter / Max Path Sum (Postorder): At each node, update a global
bestusing the path that curves through this node (left_h + right_h), and return the single best straight branch (1 + max(left_h, right_h)) up to the parent. - Lowest Common Ancestor (LCA): If
rootisnull,p, orq, returnroot. Recurse left and right: if both sides return non-null,rootis the exact split point wherepandqmeet!
Use for Diameter of Binary Tree, Balanced Binary Tree, and Binary Tree Maximum Path Sum where a path can arch through a node, but only one branch can continue upward to its parent.
best = 0
def dfs(node: TreeNode) -> int:
nonlocal best
if not node: return 0
left = max(0, dfs(node.left))
right = max(0, dfs(node.right))
best = max(best, node.val + left + right) # Arch through node
return node.val + max(left, right) # Straight branch to parent| Operation / Pattern | Time | Space | Notes |
|---|---|---|---|
| DFS Traversal (Pre/In/Postorder) | O(N) | O(H) stack | H = tree height (O(log N) balanced, O(N) skewed) |
| Level-Order BFS | O(N) | O(W) queue | W = maximum width of any level in the tree |
5. Practice On Your Own (Curated Submodule Problems)
| Status | Problem | Difficulty | Complexity | Hint? | Links & Notes |
|---|---|---|---|---|---|
Maximum Depth of Binary Tree DFS Traversals & Bottom-Up Recursion | Easy | T: O(N) S: O(H) | |||
Diameter of Binary Tree DFS Traversals & Bottom-Up Recursion | Easy | T: O(N) S: O(H) | |||
Binary Tree Level Order Traversal Level-Order BFS (Queue) | Medium | T: O(N) S: O(N) | |||
Lowest Common Ancestor of a Binary Tree Lowest Common Ancestor (LCA) | Medium | T: O(N) S: O(H) |