computer-science/big-o-how-to-tell-if-your-code-will-survive-1-000-times-more-data.md

Big O: how to tell if your code will survive 1,000 times more data

Computer science · 4 min read ·

Your code works on 10 items, then crawls on 10,000. Big O is the short way programmers describe how the number of steps grows as the input grows.

Run two duplicate-finders in your browser, count their real steps at four sizes, and see why a loop inside a loop turns 1,000 items into half a million steps while a set keeps it at 1,000.

Orange bar of 499,500 steps beside a tiny green bar of 1,000 steps, with a steep curve and a straight line

Your program works on 10 items. It works on 100. Then someone gives it 10,000 and it takes minutes. Nothing is "broken": the code simply grows faster than you expected. Programmers have a short way to talk about this called Big O, and it is much simpler than its reputation.

Count steps, not seconds

How long code takes depends on your computer, your language and what else is running. So instead of seconds, we count steps: one comparison, one lookup, one addition. Then we ask a single question: when the input gets bigger, how fast does the number of steps grow?

We call the input size n. If you have 1,000 names in a list, n is 1,000. Big O is a label for the shape of the growth, written O(...) and read "order of". It ignores small details like "plus 3 steps" and keeps only what dominates when n gets large.

Two ways to find a duplicate

Here is a real problem: does a list contain the same value twice? The first version compares every item with every item after it.

def has_duplicate_slow(items):
    steps = 0
    for i in range(len(items)):
        for j in range(i + 1, len(items)):
            steps += 1                      # one comparison
            if items[i] == items[j]:
                return True, steps
    return False, steps

The second version walks the list once and remembers what it has seen in a set, a collection that can answer "have I seen this?" in about one step regardless of its size (the hash tables article explains how).

def has_duplicate_fast(items):
    steps = 0
    seen = set()
    for x in items:
        steps += 1                          # one look-up
        if x in seen:
            return True, steps
        seen.add(x)
    return False, steps

We ran both in Python on lists with no duplicates (the worst case, because they must check everything). The step counts were:

nslowfast
104510
1004,950100
1,000499,5001,000

Look at what happened when n grew 10 times. The fast version grew 10 times too. The slow version grew about 100 times. That is the whole idea of Big O.

Try it yourself

The figure below runs both functions for real, in your browser, and counts the steps. Pick a size and watch the bars.

The common shapes

Most code you meet falls into a handful of shapes. Here is how many steps each takes (the "log" ones use base 2, rounded up):

NameBig On = 10n = 1,000n = 1,000,000
constantO(1)111
logarithmicO(log n)41020
linearO(n)101,0001,000,000
n log nO(n log n)4010,00020,000,000
quadraticO(n²)1001,000,0001,000,000,000,000

Each has a familiar example. Reading items[0] is O(1): the list can be any size and it is one step. Binary search (covered here) is O(log n): doubling the list adds only one more guess. A single loop over a list is O(n). Good sorting algorithms are O(n log n). A loop inside a loop over the same data is O(n²), which is exactly what our slow function did.

Notice the last column. A million items is nothing for a linear loop, but a quadratic one needs a trillion steps. That is the gap between "instant" and "go make a coffee, then lunch".

What Big O does not say

Big O is a guide to growth, not a stopwatch. For tiny inputs, a simple O(n²) loop can beat a clever O(n) method, because the clever one has setup costs. Two O(n) functions can still differ by a factor of 50 in real time. And Big O usually describes the worst case: our duplicate checkers stop early if they find a repeat on the first look.

So what should you do with this?

You do not need to calculate anything formally. Build one habit: when you write a loop, ask what is inside it. If the answer is "another loop over the same data" (or a call that secretly loops, like searching a list with in), you have probably written O(n²). That is fine for 50 items and worth a second look for 50,000. Often, as in our example, the fix is a better container, such as a set or dictionary, rather than cleverer code.

$ ls computer-science/

see all →
computer-science/merge-sort-how-splitting-a-list-in-half-again-and-again-sorts-it-with.md Merge sort: how splitting a list in half again and again sorts it with far less work How do you sort 10,000 numbers without making millions of comparisons? Merge sort never sorts a big pile. It splits the list until every… 5 min read · 27 Oct computer-science/hash-tables-how-a-computer-finds-one-name-among-thousands-without-chec.md Hash tables: how a computer finds one name among thousands without checking them all Your phone finds one contact among thousands without reading them all. The trick is a hash table: a row of numbered slots and a small… 6 min read · 24 Oct computer-science/stacks-and-queues-why-undo-takes-the-newest-item-and-a-printer-takes-t.md Stacks and queues: why undo takes the newest item and a printer takes the oldest Press undo and the last thing you typed disappears first. Send documents to a shared printer and the first one is printed first. Both are… 5 min read · 20 Oct computer-science/breadth-first-search-how-a-maze-solver-finds-the-shortest-way-out.md Breadth-first search: how a maze solver finds the shortest way out How does a maze solver, or a map app, find the shortest route and not just any route? The answer is breadth-first search: explore every… 6 min read · 17 Oct computer-science/binary-search-how-to-find-one-number-in-a-million-with-20-guesses.md Binary search: how to find one number in a million with 20 guesses Guessing a number between 1 and 1,000,000 sounds like it could take a million tries. With binary search it takes at most 20. Step through a… 4 min read · 14 Oct computer-science/recursion-why-fib-30-makes-2-7-million-calls-and-how-a-notebook-fixes.md Recursion: why fib(30) makes 2.7 million calls, and how a notebook fixes it A function that calls itself sounds like an endless loop, but it works when every call gets a smaller problem and one case is simple enough… 5 min read · 8 Oct