Big-O notation for everyday code, explained
Big-Oⓘ answers one question: as the data grows, how fast does the work grow? Not seconds on a wall clock — that changes with the machine — but the shape of the growth. Once you can read the shape, you can tell at a glance whether code that's smooth at 10 rows will still be smooth at 10 million.
The good news: nearly all everyday code falls into a handful of shapes, and each shape is born from a
pattern you can spot on sight — if/else, a single loop, a nested loop, recursionⓘ, and binary searchⓘ.
Let's take them one at a time: the code, the graph, then why that code produces that shape.
O(1) — constant time
Pattern: one decision with a fixed number of branches. if/else, switch, array access by index,
a hash-map read or write.
function paymentStatus(order) {
if (order.paid) return "paid"
return "unpaid"
}
O(log n) — logarithmic
Pattern: each step throws away half of the remaining work. The classic is binary search and operations on a balanced tree.
function search(sorted, target) {
let lo = 0, hi = sorted.length - 1
while (lo <= hi) {
const mid = (lo + hi) >> 1
if (sorted[mid] === target) return mid
if (sorted[mid] < target) lo = mid + 1
else hi = mid - 1
}
return -1
}
O(n) — linear
Pattern: a single loop that touches each item exactly once.
function total(numbers) {
let sum = 0
for (const n of numbers) sum += n
return sum
}
O(n log n) — linearithmic
Pattern: "divide then combine." Good sorting algorithms (merge sort, quicksort) live here.
const sorted = [...numbers].sort((a, b) => a - b)
// merge sort: splits the data into log n levels,
// then merges n items at each level
O(n²) — quadratic
Pattern: a loop inside a loop, pairing each item with every other item.
function hasDuplicate(arr) {
for (let i = 0; i < arr.length; i++)
for (let j = i + 1; j < arr.length; j++)
if (arr[i] === arr[j]) return true
return false
}
O(2ⁿ) — exponential
Pattern: branching recursion — each call spawns several new calls.
function fib(n) {
if (n < 2) return n
return fib(n - 1) + fib(n - 2)
}
The leaderboard
Stacked side by side, the order is plain — from costs that barely move to costs that explode:
A few rules of thumb you can apply while reading code:
- One loop adds a factor of n.
- Nested loops multiply by n again (two levels → n², three → n³).
- Halving each step divides it down to log n (binary search, balanced trees).
- "Divide then combine" gives n log n (good sorts).
- Branching recursion explodes into exponential — usually a sign you need memoization or a different approach.
And don't forget: O(1) wins asymptotically, but constants still matter in the real world. A lean O(log n) can beat a heavy O(1) for every realistic n. Big-O tells you how code scales, not exactly how fast it runs today.
Sources