Skip to main content
← Informatics

FOLLOW EACH STEP

Time complexity

If we give an algorithm more data, how much more work will it need? We will count the work first, then introduce the notation that describes its growth.

01

Begin with a search.

An algorithm is a sequence of instructions for solving a problem. Suppose we have a list of numbers and want to find a particular one. Linear search starts at the first item, compares it with our target, then moves to the next item if they differ.

Let nn be the number of items: the input size. Here one piece of work is one comparison with an item. Let T(n)T(n) denote the number of these comparisons. We are counting work, not elapsed seconds.

Find 21
Comparisons so far
0
Worst case for this n
10
Latest comparisonFoundBlue = already checked · Small number = index, starting at 0

Press Play or Step. We are looking for 21; no comparison has happened yet.

0 / 10 comparisons

Choose the last element. With 5 items, we compare 5 times; with 10 items, 10 times. If there are n items, finding the last one—or confirming that a target is absent—requires n comparisons. This is the worst case: the most work needed among inputs of the same size.

Tworst(n)=n⟹O(n)T_{\mathrm{worst}}(n)=n\qquad\Longrightarrow\qquad O(n)

This growth is linear: doubling the list doubles the worst-case comparison count. We describe that bound as O(n), read “big O of n”. The expression inside O tells us a growth scale. It is not the name of a particular algorithm.

02

What changes when one loop is inside another?

A for loop repeats a block of instructions. Now let the outer loop repeat n times. Inside each repetition, another loop repeats n times. Watch the inner loop finish a whole row before the outer loop moves to the next row.

n×n=5×5=25n\times n=5\times 5=25
Completed loop bodies0
0,0
0,1
0,2
0,3
0,4
1,0
1,1
1,2
1,3
1,4
2,0
2,1
2,2
2,3
2,4
3,0
3,1
3,2
3,3
3,4
4,0
4,1
4,2
4,3
4,4
for i = 0 … n−1: for j = 0 … n−1: mark(i, j)

The outer loop chooses a row. For that row, the inner loop visits every column. One coloured square means one execution of mark(i, j).

No square has been marked yet.

0 / 25 loop bodies
n+n+⋯+n⏟n times=n×n=n2⟹O(n2)\begin{gathered}\underbrace{n+n+\cdots+n}_{n\text{ times}}=n\times n=n^2\\\Longrightarrow\quad O(n^2)\end{gathered}

We assumed that marking one square takes a fixed amount of work, independent of n. There are n rows with n squares each. Doubling n doubles both dimensions, so the body runs four times as often. This is quadratic growth. Checks and increments add work, but do not change the quadratic leading growth.

What if the two loops are consecutive, not nested?

The first does n pieces of work, then the second does n more. The total is 2n, not n². Its growth is still linear: O(n). Nesting matters because the whole inner loop repeats for every outer iteration.

03

Can one comparison remove many possibilities?

It can, if the array is already sorted from small to large and we can access its middle directly. Compare the middle value with the target. If it is too small, every value to its left is also too small. Discard that part. If it is too large, discard the right part. Repeat with the remaining interval. This is binary search.

Find 33
Comparisons so far
0
Worst case for this n
5
Latest comparisonFoundDimmed = ruled out · Small number = index, starting at 0

Press Play or Step. We are looking for 33; no comparison has happened yet.

16
0 / 5 comparisons

To see the growth, first use an ideal halving calculation. After one halving, about n/2n/2 candidates remain; after two, about n/4n/4. If cc is the number of halvings needed to reach one candidate, then:

n(12)c=1⟹2c=n⟹c=log⁡2n\begin{gathered}n\left(\frac12\right)^c=1\\\Longrightarrow\quad 2^c=n\quad\Longrightarrow\quad c=\log_2 n\end{gathered}

The logarithm answers a question: “2 raised to which power gives n?” For 8 candidates, 8 → 4 → 2 → 1 gives three ideal halvings, because 2³ = 8. Doubling the input adds only one halving. That is much slower growth in work than checking twice as many items.

A halving count is not always the exact comparison count.

Array lengths are integers, and the final candidate may still need a comparison. The standard binary search above needs at most ⌊log₂ n⌋ + 1 comparisons for n ≥ 1: for 8 items, at most 4. The floor symbol ⌊ ⌋ means round down. Rounding and that extra 1 do not change the logarithmic growth, so the worst-case bound is O(log n).

The sorting must already be done. Sorting an unsorted input costs additional work, which this search count does not include. Different fixed logarithm bases differ only by a constant factor.

04

But do we always reach the last item?

Of course not. Return to linear search and choose the first item: one comparison finds it, whatever the list length. Its best case is O(1), meaning bounded work independent of n. A middle target and an absent target can require very different amounts of work on equally long lists.

Suppose a family of inputs always makes the search stop 12 items before the end. For n > 12, the count is n − 12. Those 12 saved comparisons are fixed; when n grows, the n term is what grows. We therefore simplify its growth description to O(n). Writing O(n − 12) describes the same asymptotic class here, but hides the simple linear pattern.

n = 20n − 12 = 8Saved fraction: 60.0%
n = 100n − 12 = 88Saved fraction: 12.0%
n = 1000n − 12 = 988Saved fraction: 1.2%

Time complexity describes how the work of an algorithm grows with input size. Big O gives an eventual upper bound on that growth, up to a fixed multiplier. It does not by itself mean “worst case”: we chose worst-case work for our search comparisons. We should always say which case and which operation we are counting.

T(n)≤C g(n)(n≥n0)⟹T(n)∈O(g(n))\begin{gathered}T(n)\le C\,g(n)\quad(n\ge n_0)\\\Longrightarrow\quad T(n)\in O(g(n))\end{gathered}

Here C>0C>0 is a fixed multiplier and n0n_0 is a fixed starting size; neither changes with n. The function g(n) supplies the growth scale. An upper bound need not be the closest one: linear work is also bounded by a quadratic function eventually, but O(n) describes it more informatively.

log⁡2n\log_2 n
4
nn
16
n2n^2
256

The three bars share one linear scale, from 0 to n². The scale stretches when n changes; the numbers are the actual function values. A short bar has not stopped growing.

nlog⁡2n\log_2 nnnn2n^22n2^n
4241616
83864256
1641625665,536
3253210244,294,967,296

For a polynomial work count with fixed coefficients, the highest power eventually dominates the lower powers. We can check this without guessing. Suppose the count is 3n² + 5n + 12. When n ≥ 1, n ≤ n² and 1 ≤ n², so:

3n2+5n+12≤3n2+5n2+12n2=20n23n^2+5n+12\le 3n^2+5n^2+12n^2=20n^2

The multiplier 20 stays fixed, so the count is O(n²). This is the same leading-growth idea explored in Limits: relative growth. Exponential, power, root, and logarithmic expressions grow at different rates. We compare their eventual growth, not just the steepness of a short piece of graph.

Check your understanding: the input doubles.

Linear growth multiplies by 2; quadratic growth multiplies by 4; log₂ n increases by 1. These are growth-function comparisons, not promises that every real computer runs in precisely those time ratios.