Average-Case Analysis

Worst-case analysis is the pessimist's tool: it names the single most hostile input and reports how badly the algorithm does on it. That is exactly what you want for a flight controller or a cryptographic primitive. But it can be wildly misleading for everyday code. Quicksort's worst case is \Theta(n^2), yet it is the sort the standard libraries reach for — because on a typical input it flies. To capture "typical" we stop looking at one adversarial input and instead average over all inputs, weighted by how likely each is.

Average-case analysis treats the running time as a random variable — a function of a randomly drawn input — and computes its expectation. The whole subject rests on two astonishingly powerful, almost embarrassingly simple tools: linearity of expectation and indicator random variables. Master those two and a surprising number of "hard" counting problems collapse into a couple of lines of arithmetic.

Running time as an expectation

Fix an input distribution — a probability for each possible input of size n. (The most common assumption is the uniform one: every ordering, every key, equally likely.) Let T(I) be the running time on input I. The average-case cost is the expected value

T_{\text{avg}}(n) \;=\; \mathbb{E}[T] \;=\; \sum_{I:\,|I|=n} \Pr[I]\cdot T(I).

Written like that it looks hopeless — the sum ranges over an exponential number of inputs. The trick is never to evaluate it directly. Instead we break T into a sum of tiny pieces, take the expectation of each piece, and add them back up. That is where linearity earns its keep.

Indicator random variables — the workhorse

An indicator for an event A is the variable

X_A = \begin{cases} 1 & \text{if } A \text{ happens},\\ 0 & \text{otherwise.}\end{cases}

Its expectation is not something to compute — it simply is the probability of the event: \mathbb{E}[X_A] = 1\cdot\Pr[A] + 0\cdot\Pr[\lnot A] = \Pr[A]. The whole method is a three-step ritual:

The beauty is that the individual events are often correlated in a knotted, terrifying way — and it does not matter, because linearity never asked about independence.

Worked example 1 — expected length of a hash-table chain

Throw n keys into a hash table with m slots under simple uniform hashing, so each key lands in a uniformly random slot. What is the expected number of keys sharing a fixed slot s? Let X_i = 1 iff key i hashes to s. Then \Pr[X_i = 1] = 1/m, so

\mathbb{E}\!\left[\sum_{i=1}^{n} X_i\right] = \sum_{i=1}^{n}\frac{1}{m} = \frac{n}{m} = \alpha,

the load factor. So an unsuccessful search touches on average 1 + \alpha elements — constant time whenever m = \Theta(n). That single line is the entire justification for why hashing is "O(1) on average".

Worked example 2 — the hiring / records problem

You interview n candidates in random order, and every time you meet someone better than everyone so far, you (expensively) hire them. How many times do you hire? Equivalently: as you scan a random permutation, how many left-to-right maxima (running records) do you see? Let X_i = 1 iff candidate i is the best of the first i seen. Among those first i candidates, each is equally likely to be the largest, so

\Pr[X_i = 1] = \frac{1}{i} \quad\Longrightarrow\quad \mathbb{E}[\text{hires}] = \sum_{i=1}^{n}\frac{1}{i} = H_n \approx \ln n + \gamma.

So out of a hundred candidates you hire only about \ln 100 + 0.577 \approx 5.2 times, not fifty. The harmonic number H_n grows like \ln n — punishingly slowly. The chart shows how few records appear even as n soars.

The same H_n \approx \ln n resurfaces in the average number of comparisons in a successful binary-search-tree search on random keys, and — as you will see next — in the expected depth of randomised quicksort. It is one of the most important sums in the analysis of algorithms.

Worked example 3 — expected comparisons, and the danger of averaging the wrong thing

Consider a naive linear search for a key that is present, at a uniformly random position among the n slots. It examines k elements when the key sits at position k, each position equally likely, so

\mathbb{E}[\text{comparisons}] = \sum_{k=1}^{n} k\cdot\frac{1}{n} = \frac{1}{n}\cdot\frac{n(n+1)}{2} = \frac{n+1}{2}.

On average you scan about halfway — exactly the intuition, now proved. Note the assumption did real work: change the distribution (say, keys near the front are searched more often) and the average changes. The answer is only ever meaningful relative to the input distribution you assumed.

QuantityDecompositionExpectation
Keys in a hash slot\sum_i \mathbf{1}[\,h(i)=s\,]n/m = \alpha
Hires (records)\sum_i \mathbf{1}[\,i\text{ is a running max}\,]H_n \approx \ln n
Linear-search compares\sum_k k\cdot\mathbf{1}[\text{key at }k](n+1)/2
Fixed-point permutations\sum_i \mathbf{1}[\pi(i)=i]1

That last row is a party trick: a random permutation of n items has, on average, exactly one fixed point, for every n — because each of the n positions is fixed with probability 1/n, and n\cdot(1/n)=1. No independence required; linearity does it in a breath.

There are two ways to inject randomness, and they are often confused. Average-case analysis averages over a distribution on inputs — you assume the world hands you random data, and a clever adversary who knows your code can still pick a bad input. A randomised algorithm, by contrast, flips its own coins: the input can be anything, even adversarial, and the expectation is taken over the algorithm's internal randomness. The maths — linearity, indicators — is identical, but the guarantee is far stronger, because the adversary cannot see your coins. Randomised quicksort turns quicksort's fragile average-case bound into one that holds on every input.

A seductive shortcut: "the average input is half-sorted, and quicksort on a half-sorted array takes c steps, so the average time is c." This is wrong, and the error is deep. \mathbb{E}[T(I)] averages the running time over inputs; T(\mathbb{E}[I]) runs the algorithm on some "average input" — a different number entirely, and often not even well-defined. In general \mathbb{E}[f(X)] \neq f(\mathbb{E}[X]) unless f is linear (Jensen's inequality is the precise statement). Always average the cost, never invent a typical input and time that. Decompose into indicators and let linearity do the work.