π Big-O Notation β "How Slow Does This Get?"
Before we meet any data structure, we need a way to talk about how a recipe behaves when the pile of toys gets huge. That's all Big-O is.
π§Έ ELI5: Imagine you have 3 toys β checking every single one to find your favorite is quick, maybe 3 seconds. Now imagine you have 3 million toys. Big-O is just the answer to: "if I 1,000x the toys, does the search take 1,000x longer, the same time, or something in between?" It's not a stopwatch β it's a shape of growth. We use the letter n to mean "however many things you have."
π Real life: Big-O is why a phone book with a million names is only slightly slower to search than one with a thousand names (binary search β O(log n)), but why checking every student against every other student in a class for "who has the same birthday" gets painful fast as the class grows (O(nΒ²)).
Here's the full scale, from best to worst, each with something you already do in real life:
| Big-O | Name | ELI5 | Real-world example |
|---|---|---|---|
O(1) |
Constant | Doesn't matter how many toys exist β this is always instant. | Swiping a keycard at a door. Checking if a light switch is on. Hash map lookup. |
O(log n) |
Logarithmic | Cuts the problem in half every step. | Guessing a number 1-100 in β€7 tries. Looking up a word in a paper dictionary. Binary search. |
O(n) |
Linear | You touch every item exactly once. | Reading every page of a book once. Counting every kid in a classroom. Linear search. |
O(n log n) |
Linearithmic | Split the pile up, then do a little work on each piece. | Efficiently sorting a deck of cards (merge sort / quick sort). |
O(nΒ²) |
Quadratic | Compare every item to every other item. | Checking every student against every other student for matching birthdays. Bubble sort. |
O(2βΏ) |
Exponential | Every new item doubles your work β tries every possible combination. | Trying every possible pizza topping combination (add 1 topping = the choices double). Naive recursive Fibonacci. |
O(n!) |
Factorial | Tries every possible ordering of everything. | Trying every possible seating arrangement for n wedding guests. Brute-force Traveling Salesman. |
Why n matters at scale β say you have 1,000,000 items:
O(1) -> 1 step (instant, always)
O(log n) -> ~20 steps (binary search on a million records)
O(n) -> 1,000,000 steps (scan everything once)
O(n log n) -> ~20,000,000 steps (a good sort)
O(nΒ²) -> 1,000,000,000,000 steps (bubble sort on a million items β do NOT try this)
That jump from O(n log n) to O(nΒ²) is the reason engineers care so much about picking the right data structure β it's the difference between a page loading instantly and a server timing out.
π Pseudocode (spotting Big-O by counting loops):
function example(list): // n = length(list)
for item in list: // one loop over n items -> O(n)
print(item)
function example2(list):
for a in list: // loop 1: n
for b in list: // loop 2 nested inside: n
print(a, b) // nested loops -> O(n * n) = O(nΒ²)
πΉ Go (same shapes, real code):
package main
import "fmt"
// O(1) β constant time, no matter how big `nums` is
func firstItem(nums []int) int {
return nums[0]
}
// O(n) β linear, one pass over every item
func sum(nums []int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
// O(nΒ²) β quadratic, a loop inside a loop
func hasDuplicatePair(nums []int) bool {
for i := range nums {
for j := range nums {
if i != j && nums[i] == nums[j] {
return true
}
}
}
return false
}
func main() {
nums := []int{4, 8, 15, 16, 23, 42}
fmt.Println(firstItem(nums)) // O(1)
fmt.Println(sum(nums)) // O(n)
fmt.Println(hasDuplicatePair(nums)) // O(nΒ²)
}
β±οΈ The rule of thumb: every topic below lists its own β±οΈ Complexity. When you're choosing a data structure or algorithm for a real project, ask "how big can n get?" β O(nΒ²) is perfectly fine for 50 items and a real problem for 5,000,000.
π’ BEGINNER
Big-O gave you the ruler for measuring "how slow does this get." This tier gives you the actual toy boxes β the containers and the two slowest ways to search and sort β that every fancier structure later in this guide is built on top of. None of these seven topics are hard; each one just solves exactly one "how do I organize/find/undo this" problem.
1. Arrays
π§Έ ELI5: An array is an egg carton. It has a fixed number of slots, all lined up, each with a number on it (0, 1, 2, 3...). You can look inside slot #4 instantly because you know exactly where it is β you don't have to open every slot first.
π Real life: A parking garage with numbered spots. A row of mailboxes in an apartment building. Seats in a movie theater (Row C, Seat 12).
π Pseudocode:
array = [10, 20, 30, 40]
read array[2] // instantly returns 30
πΉ Go:
package main
import "fmt"
func main() {
parkingSpots := [5]string{"Car", "", "Bike", "", "Truck"}
fmt.Println(parkingSpots[2]) // "Bike" β instant lookup
}
π¨ C (deep dive: real-life-c-guide.md Β§6):
#include <stdio.h>
int main(void) {
const char *parkingSpots[5] = {"Car", "", "Bike", "", "Truck"};
printf("%s\n", parkingSpots[2]); // "Bike" β instant lookup, same address-math trick
return 0;
}
β±οΈ Complexity: Read by index = O(1) (instant). Insert/delete in the middle = O(n) (you have to shift everyone over, like asking every car to move up one spot).