Data structures,
in slow motion
Every chapter follows the same path: a memory diagram, an interactive visualization, Java / Python / JavaScript side by side, and worked LeetCode problems. One structure per chapter, easy to hard. You see how it sits in memory instead of memorizing a definition.
What is a data structure?
The same data, organized in different ways. The animation above is the first lesson of this course.
Watch the animation above for one full cycle. The same seven numbers never change. What changes is how they are arranged and which ones are connected. In a row, in a chain, in layers, connected to each other: that is an array, a linked list, a tree, and a graph.
So a data structure is, in one sentence, a way of organizing data. The way you organize it decides what each operation costs. A library that shelves books alphabetically makes searching fast and inserting slow. A library that stacks books in the order they arrive makes inserting fast and searching painful. There is no best structure, only the structure that fits the operations you need. This course walks through the character of each one: what it is good at, what it is bad at, and why.
Faster search usually costs slower insertion. Saving time usually costs memory. Learning data structures means learning to read the price of each trade.
Every LeetCode problem asks the same question: for this set of operations, which way of organizing the data costs the least? Every chapter works through the common ones.
A database index is a B+ tree. Redis uses hash tables and skip lists. A message queue is a queue. The undo command is a stack. You use all of them every day, through an API.
It all starts with memory
The whole course needs only one mental model: memory is a long street of numbered rooms.
Picture memory (RAM) as a street that goes on forever. Every room on the street is identical, each room has a unique number (its address), and each room holds one small item, for example one byte. The CPU is the runner: give it any room number and it reaches that room in the same amount of time. That is what RAM (random access memory) means, and it is the source of every O(1) in this course.
On the left, five rooms next to each other (how an array lives): if the first address is 1000, then element i sits at 1000 + i×4, computed in one step. On the right, scattered rooms (how a linked list lives): each room also stores where the next room is, so you can only hop from one to the next.
The most important formula in this course
address = base address + index × element size. O(1) access in an array, finding the right bucket in a hash table, and storing a tree inside an array in the heap chapter all rest on this one multiply-and-add. Learn it now: the next 14 chapters keep coming back to it.
Variables and references: the note with an address on it
Linked lists, trees, and graphs are all held together by this. Before the structures, see the difference between a box and a note.
Think of a variable as a box with a label on it. What goes into the box comes in two kinds. A small thing like 7 lives inside the box itself (a value). A large thing like an object or an array lives at some address on the memory street, and the box holds only a note with that address written on it. That note is a reference. In C it is called a pointer.
So the line b = a has two very different meanings. For a value it copies the contents. For a reference it copies the note. After the note is copied, both labels point at the same room, so a change made from either side is visible from the other. Try it yourself:
Why this section is the foundation of the course
Every node in a linked list (chapter 3) holds a note saying where the next node is. Every node in a tree holds two (left and right). Every node in a graph holds a list of them. A linked structure is just boxes scattered across memory, tied together by these notes. Once this lab makes sense, no later chapter will be out of reach.
Big-O: how to measure an algorithm
Do not count seconds. Count how the number of operations grows with n. Drag the slider and watch.
You cannot compare two algorithms by asking which one runs faster on your machine. Different machines and different inputs give different answers. Computer science asks a different question: as the input size n grows, how does the number of operations grow? That growth is written with O(...), keeping only the fastest-growing term and dropping coefficients and constants: 3n²+5n+20 becomes O(n²).
In the lab below, the six curves are the six levels you will meet again and again. Note that the y axis uses a logarithmic scale. Even so, O(2ⁿ) still leaves the top of the chart.
| Complexity | Operations at n = 32 | At n = 10⁶ (one million) | Time at n = 10⁶ * |
|---|---|---|---|
| O(1) | 1 | 1 | less than a microsecond |
| O(log n) | 5 | 19.9 | less than a microsecond |
| O(n) | 32 | 1,000,000 | 10.0 milliseconds |
| O(n log n) | 160 | 19,931,569 | 199.3 milliseconds |
| O(n²) | 1024 | 1.0×10^12 | 2.8 hours |
| O(2ⁿ) | 4,294,967,296 | 10^301006 — too large to print | longer than the age of the universe |
* Estimated at 10⁸ basic operations per second. This is why an interviewer keeps asking about the complexity of your solution.
Two common misunderstandings
(1) Big-O is not running time. It describes growth, not seconds. For small n, an O(n²) algorithm can beat an O(n log n) one. (2) A complexity is always stated for a case: worst, average, or amortized. Say which one you mean. A hash table is O(1) on average and O(n) in the worst case, and that is the classic example.
Complexity reference table
Skim it now and come back after the last chapter. By then you will be able to explain every cell.
| Structure | Access | Search | Insert | Delete | Note |
|---|---|---|---|---|---|
| Array | O(1) | O(n) | O(n) | O(n) | Access by index is what it is for. Inserting or deleting in the middle shifts the other elements. |
| String | O(1) | O(n) | O(n) | O(n) | Immutable in most languages, so any change builds a new string. |
| Linked List | O(n) | O(n) | O(1) | O(1) | Insert and delete are O(1) only when you already hold the node in front. |
| Stack | O(n) | O(n) | O(1) | O(1) | Only the top is touched, so push and pop are O(1). |
| Queue | O(n) | O(n) | O(1) | O(1) | Only the two ends are touched, so enqueue and dequeue are O(1). |
| Hash Table | — | O(1) | O(1) | O(1) | O(1) on average. If every key collides, it degrades to O(n). |
| Binary Search Tree | O(log n) | O(log n) | O(log n) | O(log n) | O(log n) while the tree stays balanced. A degenerate tree is a linked list, so O(n). |
| Heap | O(1) | O(n) | O(log n) | O(log n) | Access means reading the top. Finding an arbitrary element is not what it is for. |
| Trie | — | O(1) | O(1) | O(1) | Cost is measured by the word length L, not by how many words are stored. |
| Union-Find | — | O(1) | O(1) | — | About O(α(n)), which is effectively O(1), with path compression and union by rank. |
The table lists the complexity that is normally quoted (average or amortized for the hash table and union-find). The reason behind every cell has a diagram and a visualization in the matching chapter.
The map: 14 chapters, easy to hard
The bar shows difficulty. The stars show how often the structure appears on LeetCode. Pick any chapter to start.
How to use this course
Every chapter follows the same three steps. Do not skip one.
Intuition, then the memory diagram, then the operations one by one. For each structure, answer three questions first: what does it look like, what is it good at, and why?
Every chapter has a visual playground. Insert, delete, and traverse by hand, and watch the pointers move and the memory shift. A structure you have played with is a structure you own.
Two or three problems are worked in full, with solutions in all three languages, followed by a list of common problems. Your checkmarks are saved in this browser and counted in the sidebar.
About the three languages
The Java / Python / JS control in the top bar applies to the whole site: switch once and every code window follows. The structure itself is the same in all three languages (an array is an array, a stack is a stack). The differences are in the implementation and the standard library, and each chapter has a section that lists them one by one.
Quick check: chapter 00 quiz
✎ Chapter quiz7 questions. Get them all right to turn on the first green dot in the sidebar.
What does O(1) actually mean?
Two nested for loops each run from 0 to n-1, and the loop body is O(1). What is the total complexity?
An algorithm performs exactly 3n + 20 operations. What is its Big-O?
Binary search runs on a sorted array of 1,000,000 (10⁶) elements. In the worst case, about how many comparisons does it make? (Give a whole number.)
Which of these statements are correct? (Select all that apply.)
After running b = a (where a is an array), you change b[0] and find that a[0] changed too. Why?
Why can an array read arr[i] in O(1)?
- A data structure is a way of organizing data. The way you organize it decides what each operation costs. There is no best one, only the one that fits.
- Memory is a street of numbered rooms: address = base address + index × element size. This one formula is the shared foundation of arrays, hash tables, and heaps.
- Assigning an object copies the reference (the note with the address), not the contents. Linked lists, trees, and graphs are boxes tied together by these notes.
- Big-O describes growth, not seconds: drop coefficients, drop constants, keep the fastest-growing term. When you state a complexity, say whether it is average, worst case, or amortized.
- Memorize the six levels: O(1) → O(log n) → O(n) → O(n log n) → O(n²) → O(2ⁿ). At one million items, the difference between them is the difference between an instant and longer than the age of the universe.