Binary Trees & BSTs
- Define tree anatomy precisely: root, leaf, depth, height, subtree
- Implement all four traversals (pre/in/post-order and level-order) from scratch
- Implement BST search and insert and state why both are O(h), not O(log n)
- Explain how a BST degenerates into a linked list and what that costs
- Solve max-depth, invert-tree, and validate-BST with clean recursion
| Spaced-rep warm-up: due cards from Week 4 (recursion, stacks, linked lists) | 10 min |
| ELI5 + tech read; step through the BST-search visualizer | 18 min |
| Guided: build & traverse, then BST ops + three classics | 42 min |
| Practice: kth smallest in a BST | 18 min |
| Project: tree toolkit + tests, commit | 22 min |
| Quiz + add today's flashcards to the deck | 10 min |
Builds on: Day 26 โ Linked lists โ nodes & pointers ยท Day 27 โ Recursion & divide/conquer ยท Day 25 โ Stacks & queues (BFS preview)
Picture a company org chart: one CEO at the top, each person managing at most two reports. That is a binary tree โ every box is a node, the boxes under it are its children, and everything below one manager is that manager's subtree. Walking the chart top-to-bottom, level-by-level is one way to visit everyone; diving down one management chain before backing up is another.
Now add a sorting rule to the org chart: everyone to a manager's LEFT earns less, everyone to the RIGHT earns more โ and the rule holds for the entire left and right sides, not just direct reports. That is a binary search tree. The rule is what makes it searchable: to find the person earning 72k you never interview the whole company โ at each box you ask "less or more?" and discard half the chart, exactly like the phone-book halving you will formalize on Day 33. But the magic only works if the chart stays bushy. If every hire lands on the right side, your "tree" is really a queue of people in a hallway, and searching it means walking the whole hallway.
Trees are everywhere in your future stack: the JSON documents your APIs pass around are trees, HTML is a tree, Python parses your code into an abstract syntax tree, Postgres indexes are B-trees (Day 38), and the tries behind autocomplete (Day 30) are trees too. In interviews, tree questions are the single most common data-structure category, and they are really recursion questions in costume โ the Day 27 skill cashed in. As an FDE you will also literally walk trees: extracting fields from deeply nested customer JSON payloads is a tree traversal you will write on-site.
The org chart with a sorting rule โ find 40 in a BST
step 1 / 5A binary search tree: every node's LEFT subtree holds smaller values, RIGHT holds bigger. That one invariant is a promise we can cash in at every step. Target: 40.
Guided practice
Build a tree and walk it four ways
20 min- Create
trees_lab.pyand paste the starter code โ aTreeNodeclass and a hand-built sample tree. - Implement
inorder,preorder, andpostorderas recursive functions that append to a result list. Each is three lines of real logic. - Predict on paper what each traversal prints for the sample tree BEFORE running. Diff your prediction against reality โ mispredictions are where learning lives.
- Implement
level_orderwithcollections.deque: pop from the left, append children on the right, collect values per level. - Sanity check: run
inorderon the BST built by the starter'sinsertcalls โ the output must be sorted. Say out loud WHY (left < node < right, applied recursively).
BST ops + three classics, think-aloud
22 minWork each problem with the two-question recipe: base case? combine children's answers?
- Implement
bst_insertandbst_search(starter has signatures). Insert 50 sorted values into a fresh BST, then measure its height โ you have just built the degenerate case. Insert the same values shuffled and compare heights. - Classic 1 โ Max depth. Think aloud: "Empty tree is depth 0. Otherwise I am 1 + the deeper of my two subtrees." Write it in 3 lines.
- Classic 2 โ Invert a tree. Think aloud: "Swap my children, then ask each child to invert itself." Verify by printing level_order before/after.
- Classic 3 โ Validate BST. First write the TEMPTING wrong version (check each node against only its direct children), and break it with the starter's
traptree. Then write the correct version: pass down (lo, hi) bounds that every node must respect. This bug is the most common tree-interview mistake โ earn the scar now.
On your own
Kth smallest in a BST
18 minGiven the root of a BST and an integer k, return the kth smallest value (1-indexed). Solve it two ways: (1) the obvious way using a full traversal, then (2) an early-exit version that stops traversing the moment it has seen k values.
State the complexity of both. Test on a BST of 1..15 with k = 1, 7, 15.
Hints (only if stuck): which traversal visits BST values in sorted order? For early exit, a generator (Day 11) plus itertools.islice is elegant โ or count down k inside the recursion.
Tree toolkit for the interview repo
Create dsa/trees.py in your practice repo: TreeNode, all four traversals, bst_insert/bst_search, height, plus the three classics (max depth, invert, validate). Add test_trees.py with pytest cases including the degenerate BST (sorted inserts) and the validate-BST trap tree. In the module docstring, write a 5-line "when do I reach for a tree?" note in your own words. Commit โ Day 35's drill and Day 179's interview gym pull problems straight from this file.
Common mistakes & misconceptions
- Validating a BST by comparing each node only with its children. The invariant covers WHOLE subtrees โ pass down (lo, hi) bounds. This is the classic trap.
- Saying BST search is O(log n) unconditionally. It is O(h); only a balanced tree gives h โ log n. Sorted inserts give h = n.
- Confusing depth (node property, from root) with height (tree property, longest path down). Interviewers use both; know which is which.
- Forgetting the base case handles None, then crashing on leaf children. Every recursive tree function starts with the None check.
- Using level-order (queue) when a recursive DFS is three lines โ or recursion when the problem says "by level", which is the queue's job.
- Tracing every recursive call by hand instead of trusting the recursive contract: assume children return correct answers, combine, done.
Q1. You run an in-order traversal on a valid BST. What comes out?
Q2. You insert 1, 2, 3, ..., 1000 into an empty BST in that order. Searching it now costsโฆ
Q3. A colleague validates a BST by checking node.left.val < node.val < node.right.val at each node. Why is this wrong?
Go deeper โ curated resources
- Self-balancing trees (AVL rotations) on VisuAlgo โ โ Watch how a rotation restores balance after an insert. You need the concept, not the code โ Day 38's B-trees solve balance for databases differently.
- All four traversals implemented; in-order-on-BST-is-sorted verified
- Trap tree defeats the naive validator and passes the bounds version
- Kth smallest solved both ways with complexities stated
- Tree toolkit committed with green tests
- Quiz โฅ 2/3
โ Back: Nodes-and-pointers come straight from Day 26's linked lists โ a tree is a linked list that branches. Every traversal is Day 27's recursion recipe, and level-order is Day 25's queue earning its keep.
Forward โ: Day 30 reshapes trees into heaps and tries. Day 31 generalizes traversal to graphs (BFS/DFS). Day 33 formalizes the halving idea BSTs rely on, and Day 38 reveals the B-tree โ the BST's disk-based cousin inside every database index.
Unlocks: D30 Heaps, Priority Queues & Tries ยท D31 Graphs, BFS & DFS ยท D33 Binary Search & Variants ยท D35 Week 5 Checkpoint: Interview Drill I