programmingconcepts

§ 3.1 · Algorithms

Big O

A way to describe how an algorithm's work grows as its input grows, ignoring constant factors.

Big O notation describes how an algorithm's running time or memory grows as its input grows, ignoring constant factors and smaller terms. O(1) stays flat, O(log n) barely grows, O(n) grows in step with the input, and O(n²) quadruples when the input doubles. It lets you compare algorithms before running them on large data.

Measures
Growth of time or space
Ignores
Constants, smaller terms
Usually means
Worst case
02505007501,000016324864input size nstepsO(1)O(log n)O(n)O(n log n)O(n²)O(2ⁿ)n = 16

Drag on the chart or the slider to change n. Pick a row to highlight its curve.

Steps and time for each complexity class at the chosen input size
ClassExampleSteps at n = 16At 1 step per ns
Read a[i]11 ns
Binary search44 ns
Scan a list once1616 ns
Merge sort6464 ns
Compare every pair256256 ns
Try every subset65,53666 µs
Fig. 3.1. Each curve is a complexity class. Drag n and read the table to see how many steps each needs, and how long that takes at a billion steps per second.

Intuition

Imagine looking up a word. Reading a dictionary page by page takes longer the bigger the dictionary: double the pages, double the work. Opening it in the middle and halving the search each time barely notices the size: double the pages, one more step.

Big O names that difference. It doesn’t count seconds. It describes the shape of the growth, so you can tell which approach will still work when the input is a thousand or a million times bigger.

How to read it

Count the steps an algorithm takes for an input of size n, then keep only the part that dominates as n grows:

  1. Drop constants. 3n steps and n steps are both O(n). Constants depend on the machine and language; the shape doesn’t.
  2. Keep the biggest term. n² + 5n + 20 is O(n²). At n = 1,000, the n² part is 1,000,000 and the rest is about 5,000.
  3. Nested loops multiply. A loop over n inside another loop over n is O(n²). Two loops one after the other are O(n) + O(n), which is still O(n).
  4. Halving gives a log. If each step throws away half of what’s left, the step count is about log₂ n.

The common classes

Class Name Example Double n and the work…
O(1) constant Read a[i] stays the same
O(log n) logarithmic Binary search grows by one step
O(n) linear Find the largest value doubles
O(n log n) linearithmic Merge sort a bit more than doubles
O(n²) quadratic Compare every pair quadruples
O(2ⁿ) exponential Try every subset squares

In code

The three functions below do very different amounts of work on the same list. Count the loops:

def first(items):  # O(1)
    return items[0]


def contains(items, target):  # O(n)
    for item in items:
        if item == target:
            return True
    return False


def has_duplicate(items):  # O(n²)
    for i in range(len(items)):
        for j in range(i + 1, len(items)):
            if items[i] == items[j]:
                return True
    return False

first touches one item no matter how long the list is. contains may check every item once. has_duplicate compares every pair, about n²/2 comparisons.

Common mistakes

  1. Treating Big O as speed. It predicts how the cost scales, not how fast one run is.
  2. Forgetting the hidden loop. x in list, indexOf and list.remove are O(n) each. Inside another loop they make the whole thing O(n²).
  3. Adding when you should multiply. Loops one after the other add; loops inside loops multiply.
  4. Ignoring space. Making a copy of the input is O(n) extra memory, even when the time is fine.

Check yourself

Check yourself

An O(n²) algorithm takes 1 second on 1,000 items. About how long on 2,000 items?

Check yourself

What is the Big O of n² + 100n + 5000?

Sources

  • Cormen, Leiserson, Rivest and Stein, Introduction to Algorithms, chapter 3, “Characterizing Running Times.”
  • Donald Knuth, “Big Omicron and Big Omega and Big Theta,” ACM SIGACT News 8, no. 2 (1976): 18–24.

Newsletter

One new concept each week, by email.

Signup opens soon.