Data Structures from Scratch
Why Build What Already Exists?
JavaScript gives you Array, Map, Set, and Object out of the box. You will never ship a linked list to production. So why build one?
Because understanding why Map.get is O(1) and Array.includes is O(n) changes every architectural decision you make at scale. When you have 100,000 records and your page freezes, the cause is almost always a data structure mismatch — the wrong tool for the access pattern. Building each structure from scratch makes the performance characteristics visceral, not theoretical.
Big-O — The One Concept That Ties Everything Together
Big-O notation describes how the time or space cost of an operation grows as the input grows. Not the exact time — the shape of the growth:
The timing ratios tell the story. O(1) stays flat. O(n) doubles as input doubles. O(n²) would take hours at 100,000 items — which is why we cap it. Every data structure below is designed to give you O(1) or O(log n) for its primary operation.
Linked List — Sequential Access, O(1) Insert at Head
An array stores elements in contiguous memory — fast random access (arr[i] is O(1)) but slow insert/delete in the middle (everything shifts). A linked list stores elements anywhere in memory, connected by pointers — O(1) insert/delete at any known position, but O(n) to reach position i.
Stack — Last In, First Out
A stack is an array with restricted access: you can only push to the top and pop from the top. O(1) for both. The call stack in JavaScript is literally this data structure — every function call pushes a frame, every return pops one:
Queue — First In, First Out
A queue is the opposite discipline: add to the back, remove from the front. O(1) enqueue, O(1) dequeue. Every task queue, event loop, and breadth-first search uses this structure:
The head-pointer queue pulls ahead dramatically as size grows — shift moves every remaining element in memory; the pointer just increments an integer.
Binary Search Tree — O(log n) Search, Insert, Delete
A BST organises data so that for every node, all values in the left subtree are smaller and all values in the right subtree are larger. This invariant makes search O(log n) — each comparison eliminates half the remaining nodes:
Hash Map — O(1) Everything via Hashing
JavaScript's Map and {} are hash maps. The engine hashes your key to an integer, uses that as an array index, and stores the value there — O(1) get, set, and delete. The cost: extra memory for the hash table, and occasional O(n) when the table must resize. Building one reveals the mechanism:
Graph — Connections Between Anything
A graph models relationships: social networks, road maps, dependency trees, the web itself. Nodes (vertices) connected by edges, which may be directed or weighted:
Priority Queue — Always Pop the Most Important
A priority queue returns the highest-priority item first, not the most recently added. The efficient implementation is a binary heap — a tree maintained in an array where every parent is smaller (min-heap) or larger (max-heap) than its children:
Choosing the Right Data Structure
What You Have Learned
Data structures are not academic — they are the difference between a feature that handles 100 users and one that handles 100,000.
The key ideas:
- Big-O describes growth shape, not absolute time — O(1) is constant, O(log n) halves the problem each step, O(n) scales linearly, O(n²) becomes unusable at scale
- Linked list: O(1) insert at known position, O(n) access by index — use when you insert/delete frequently at known nodes
- Stack: O(1) push and pop, LIFO — the call stack, undo history, bracket matching
- Queue: O(1) enqueue and dequeue (with head pointer), FIFO — task queues, BFS, event loops
- BST: O(log n) search, insert, delete — in-order traversal yields sorted output
- HashMap: O(1) get, set, delete via hashing — JavaScript's
Mapand{}are both hash maps - Graph: models connections — BFS finds shortest paths, DFS explores all reachable nodes
- Heap / Priority Queue: O(1) peek at min/max, O(log n) insert and pop — the right tool whenever you need "give me the most important thing"
In the next lesson: Parsing & ASTs — how JavaScript reads your code before running it. Build a lexer, a parser, and a small interpreter. Understand how Babel, ESLint, and TypeScript process source code — and why this knowledge unlocks metaprogramming at the deepest level.