DataData/00 · Start here
INTERACTIVE COURSE · 14 CHAPTERS

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.

14
chapters, easy to hard
127
common LeetCode problems
3
languages: Java / Py / JS
50+
interactive visualizations
§01

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.

REASON 01
⚖️ Every choice is a trade

Faster search usually costs slower insertion. Saving time usually costs memory. Learning data structures means learning to read the price of each trade.

REASON 02
The shared language of interviews

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.

REASON 03
The foundation of real systems

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.

§02

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.

One street, two ways of living on it
71000
21004
91008
41012
11016
·1020
·1024
9→?1028
·1032
5→?1036

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.

§03

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:

Reference lab: labels, notes, and boxes
ab{ val: 7 }@1000{ val: 3 }@2048
Right now a and b each point at their own box. Use the buttons below and watch what happens to the note that holds the address.
references.py
1# Python: everything is an object; a variable is a name bound to an object
2x = 7
3y = x # both names point at the same int 7 (int is immutable)
4y += 10 # y is rebound to a new object 17; x is unchanged
5
6a = [7]
7b = a # the same list object, reached by two names
8b[0] += 10
9print(a[0]) # 17
10print(a is b) # True -- "is" asks whether it is the same object
Rule: in Python every variable holds a reference. What differs is whether the object is mutable. int, str, and tuple are immutable, so changing them creates a new object. list, dict, and set are mutable, so a change happens in place and every name pointing at that object sees it.

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.

§04

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.

Big-O growth lab: drag n and watch the curves separate
1010²10^410^610^810^10n = 32
ComplexityOperations at n = 32At n = 10⁶ (one million)Time at n = 10⁶ *
O(1)11less than a microsecond
O(log n)519.9less than a microsecond
O(n)321,000,00010.0 milliseconds
O(n log n)16019,931,569199.3 milliseconds
O(n²)10241.0×10^122.8 hours
O(2ⁿ)4,294,967,29610^301006 — too large to printlonger 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.

§05

Complexity reference table

Skim it now and come back after the last chapter. By then you will be able to explain every cell.

StructureAccessSearchInsertDeleteNote
ArrayO(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.
StringO(1)O(n)O(n)O(n)Immutable in most languages, so any change builds a new string.
Linked ListO(n)O(n)O(1)O(1)Insert and delete are O(1) only when you already hold the node in front.
StackO(n)O(n)O(1)O(1)Only the top is touched, so push and pop are O(1).
QueueO(n)O(n)O(1)O(1)Only the two ends are touched, so enqueue and dequeue are O(1).
Hash TableO(1)O(1)O(1)O(1) on average. If every key collides, it degrades to O(n).
Binary Search TreeO(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).
HeapO(1)O(n)O(log n)O(log n)Access means reading the top. Finding an arbitrary element is not what it is for.
TrieO(1)O(1)O(1)Cost is measured by the word length L, not by how many words are stored.
Union-FindO(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.

§06

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.

§07

How to use this course

Every chapter follows the same three steps. Do not skip one.

Understand it first

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?

Then play with it

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.

✍️ Then practice

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.

§08

Quick check: chapter 00 quiz

✎ Chapter quiz

7 questions. Get them all right to turn on the first green dot in the sidebar.

QUESTION 01 / 7

What does O(1) actually mean?

QUESTION 02 / 7

Two nested for loops each run from 0 to n-1, and the loop body is O(1). What is the total complexity?

QUESTION 03 / 7

An algorithm performs exactly 3n + 20 operations. What is its Big-O?

QUESTION 04 / 7

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.)

QUESTION 05 / 7

Which of these statements are correct? (Select all that apply.)

QUESTION 06 / 7

After running b = a (where a is an array), you change b[0] and find that a[0] changed too. Why?

QUESTION 07 / 7

Why can an array read arr[i] in O(1)?

What to take away from this chapter
  • 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.