Module · 5 lessons

Recursion & Trees

A hash answers one question instantly and another not at all. Learn why a dict cannot find 'every trip between 8 and 9am', how order buys log-time search and cheap ranges, how sorting data larger than memory works by merging runs, and how an index turns a scan into a seek — building a real time-range index over the NYC taxi month.

At a glance

Level
Beginner to Intermediate
Lessons
5 lessons
Time to complete
1 week
Cost
Free forever · no sign-up

Welcome to Recursion & Trees, the seventh module — which begins by finding the limit of Module 6’s best idea. Hashing was a genuine triumph: a dict finds a zone by id in constant time whether it holds ten entries or ten million, and it beat a list scan by 19.2x on the real month. But ask it a slightly different question — give me every trip between 08:00 and 09:00 — and it collapses. It cannot help at all. A hash table computes a slot from a key precisely by scattering neighbouring keys as far apart as possible, so nothing about where 08:00 landed tells you where 08:01 lives. Answering a range means checking every key, and you are back to the scan you paid an index to avoid.

What a range query needs is the one property hashing deliberately destroys: order. Order is what lets you rule out half the data with a single comparison, bracket a window with two probes, merge two sorted streams by always taking the smaller head, and skip a block of a file because its largest value is smaller than what you’re looking for. Ordered data lives in trees — and in their flat, cache-friendly cousin, the sorted array — which is why every real database ships a B-tree index rather than only a hash. Trees are also recursive by nature: a tree is a node holding smaller trees, so the code that walks one is naturally recursive too. That is why this module teaches recursion first.

Across five lessons you’ll earn each idea on CityFlow’s real taxi data: recursion that matches the shape of the data without blowing the stack, binary search that finds a timestamp in log time, an external sort that orders more rows than fit in memory, and the min/max statistics already sitting in the Parquet file that let you skip whole row groups. Then you’ll assemble them into a time-range index that answers “trips 8-9am” without ever loading the month. Start with Lesson 1, where recursion turns out to be slower than a loop — and worth reaching for anyway, for reasons that have nothing to do with speed.

Lessons in this module

1 Recursion for Data Module 6's dict answers exact matches in 0.071 us but needs 700x that for a range query — so this lesson starts the move to trees by teaching recursion on CityFlow's real 3-level zone hierarchy, where a recursive walk costs 1.03x an explicit loop, a per-row recursion costs 6.83x and dies at 999 of 2,964,624 trips. 2 Binary Search Trees Watch a dict fail at range queries on 2,964,624 real NYC taxi trips, build a recursive BST that answers in log time, then discover the honest twist — bisect on a sorted array beats the hand-rolled tree 4.9x and pulls the 2,440 trips between 08:00 and 09:00 out of the month in 5.18 us instead of 0.192 s. 3 Trees for Sorting & Merging Sort 2,964,624 real NYC taxi timestamps without ever holding them in memory — hand-roll the two-run merge, build a heap-based k-way merge, then run a real external sort that peaks at 22.1 MB instead of 166.1 MB (7.5x less) while taking 2.7x longer, and measure why Timsort is 2.73x faster on the file's real order. 4 Indexing a File Build a real byte-offset index over a 14.6 MB file and seek instead of scan (5,870x), discover a dense index costs 143% of the data it indexes, fix it with a sparse one 997x smaller, then find that CityFlow's real parquet file ships no statistics at all — and that sorting is what takes predicate pushdown from 100% of rows read to 33.7%. 5 Guided Project: A Time-Range Index Over the Taxi Data Build CityFlow's time-range index over 2,964,624 real January 2024 taxi trips: discover the month is not actually sorted by pickup time, sort and cluster it once for 0.93 s, then answer any 1-hour window in 0.730 ms by reading 2.2% of the file instead of 100%.
Achievement

Complete all 5 lessons to finish the Recursion & Trees module.

Start module
Sponsor

Keep DATATWEETS free. Help fund practical data, AI, and engineering lessons for learners worldwide.

Buy Me a Coffee at ko-fi.com