An algorithm that works on a small example may become unusable when
its input grows. Growth analysis asks how required work, memory,
communication, or another resource depends on the size and shape of the
input. It supports machine-independent comparison while deliberately
ignoring many implementation details.
Asymptotic analysis and measurement are complementary. Analysis
explains long-run scaling under a model; experiments reveal constants,
memory behaviour, compiler effects, and the input range that matters in
practice.
Learning goals
After studying this note, you should be able to:
choose meaningful input-size parameters and a cost model;
distinguish worst-case, average-case, expected, and amortised
claims;
derive a cost function from loops, calls, and common sums;
use
,
,
,
,
and
precisely;
prove a simple asymptotic bound from its definition;
compare standard growth classes and practical crossover points;
analyse time and auxiliary space separately;
expand a simple divide-and-conquer recurrence; and
design timing experiments without presenting them as proofs.
Prerequisites
You should understand basic algebra, functions, powers, logarithms,
loops, arrays, and recursion. The preceding orientation note introduced
inputs, representations, and the unit-cost RAM model.
Input size and cost models
Before counting work, decide what the input size means. For sorting,
is normally the number of records. A graph may require two parameters,
and
.
A matrix multiplication involves dimensions, not merely one generic
.
For an integer
,
the representation length is
bits when
.
This last distinction prevents misleading claims. An algorithm taking
steps is exponential in the bit length of
,
not polynomial in it. Such a bound is often called
pseudo-polynomial when it is polynomial in numeric
values but not in the length of their encoding.
A cost model states which operations are counted.
Possibilities include comparisons, array accesses, arithmetic operations
on machine words, allocated words, block transfers, messages, or calls
to an expensive subroutine. A result is meaningful only together with
its model.
Cases, probability, and
sequences
Inputs of the same size can produce different costs:
the worst-case cost is the maximum over inputs of
size
;
the best-case cost is the minimum;
the average-case cost is an expectation over a
stated probability distribution on inputs; and
the expected cost of a randomized algorithm fixes
an input and averages over the algorithm’s random choices.
These expectations are not interchangeable. “Random-looking test
data” is not a mathematical input distribution, and random pivot
selection is not an assumption that the original input is random.
Amortised analysis uses no probability. It bounds
the total cost of every allowed operation sequence and assigns that
total across the operations. A single operation may remain expensive
even when the amortised cost per operation is small.
Each of these labels applies to a cost function, not directly to a
line of code. State the size parameter first, then say which inputs or
random choices the function quantifies over.
From code to a cost function
Count executions rather than multiplying visible loop bounds
mechanically. Consider:
for i = 1 to n:
for j = 1 to i:
do constant work
The number of executions of the inner operation is
Therefore the running time is
.
Two nested loops happen to give a quadratic result here, but the sum
explains why; if the inner bound were
,
the result would be different.
Consecutive phases add. Nested independent work usually multiplies.
Conditional branches require a case assumption: a worst-case analysis
uses the most costly feasible branch, while an expected analysis needs
probabilities.
A small mathematical toolkit
Several sums recur throughout algorithm analysis:
The geometric series explains dynamic-array resizing and levels of
complete trees. The harmonic sum appears in probabilistic analyses.
Useful logarithm rules are
and
Changing a fixed logarithm base multiplies by a constant, so the base
normally disappears inside asymptotic notation.
Asymptotic definitions
Assume
and
are non-negative for sufficiently large
.
Formally,
is a set of functions. The notation
is therefore clearest, although textbooks conventionally write
as one-way shorthand. It is not an algebraic equality: from
one may not infer
.
Upper, lower, and tight
bounds
We have
if constants
and
exist such that
We have
if constants
and
exist such that
Finally,
when both bounds hold. Equivalently, positive
exist with
Worst case says which cost function is under discussion; Big O says
how a function is bounded. Big O does not itself mean worst case.
Strict asymptotic relations
We have
if, for every constant
,
some
makes
Thus
becomes smaller than every positive constant multiple of
.
Conversely,
if, for every
,
eventually
.
When
eventually and the relevant limit exists,
implies
.
A finite positive limit implies
,
and an infinite limit implies
.
The constant-based definitions still apply when a ratio limit does not
exist.
Worked proof from the
definition
Let
.
For every
,
Choosing
and
proves
.
Also
,
so
and
prove
.
Hence
The constants need only work eventually; they need not be smallest
possible.
Common growth classes
For fixed
,
,
and
,
Here
informally denotes
.
The condition
is essential: for
,
grows faster than
.
Growth
Informal name
Typical source
constant
one indexed array access
logarithmic
repeatedly halve a range
linear
inspect every item once
linearithmic
balanced divide and conquer
quadratic
inspect every pair
exponential
enumerate all subsets
factorial
enumerate all permutations
Dominant terms determine a sum’s asymptotic class when terms are
eventually non-negative. Thus
This does not make lower-order terms or constants irrelevant at
finite sizes.
Recurrences from first
principles
A recurrence describes a recursive call tree. It must include a base
case. For powers of two, consider
At level
,
there are
subproblems of size
.
Their non-recursive work totals
There are
non-leaf levels, plus
constant-cost leaves. Therefore
For arbitrary
,
floors and ceilings change constants but not this asymptotic result. A
later note gives the Master theorem; expanding a few levels first is
safer than applying a memorised formula to a recurrence that does not
fit it.
Worked comparison:
constants versus growth
Suppose two implementations are modelled by
Although
,
A is faster only when
.
At
,
the left side is
,
so B wins in this model. At
,
it is
,
so A wins. Asymptotic order predicts eventual behaviour; an exact model
or measurement locates the relevant crossover.
Time, space, and trade-offs
Analyse different resources separately. Iteratively summing an array
takes
time and
auxiliary space. A direct recursive version still takes
time but uses
call-stack space. An algorithm may deliberately spend memory to save
recomputation, or spend time to reduce storage.
Also distinguish auxiliary space from total storage.
If an input array already occupies
words, saying an in-place scan uses
auxiliary space does not mean the entire computation occupies constant
memory.
Measurement and asymptotic
analysis
A useful timing experiment should:
vary input size over a substantial range;
state how inputs and cases are generated;
separate setup from the operation being measured where
appropriate;
repeat trials and report variability;
keep environments comparable;
label axes and units;
consider logarithmic axes for wide ranges; and
explain deviations from the analytical model.
A straight line on a log-log plot can suggest polynomial growth, with
its slope suggesting an exponent. It cannot prove an asymptotic bound:
measurements cover finitely many inputs, and different functions can
look similar over a restricted range.
Connections
Dynamic arrays in the next note use a geometric sum for amortised
analysis.
Merge sort, quicksort, and selection lead to recurrences and
expected-cost calculations.
Graph algorithms commonly require bounds in both
and
.
Succinct structures and string algorithms make word size and bit
complexity explicit.
Heuristic methods require empirical comparisons because asymptotic
cost alone says nothing about solution quality.
Common mistakes
Treating
as a symmetric algebraic equality or an exact runtime.
Saying “Big O means worst case.” Case selection and function bounds
are different.
Giving a loose upper bound when a tight bound is available.
Measuring numeric magnitude instead of input representation
length.
Multiplying loop limits without checking dependencies.
Confusing average-case, expected randomized, and amortised
analysis.
Omitting recursion-stack or auxiliary-space costs.
Assuming the asymptotically better algorithm wins for every
practical
.
Presenting a fitted timing curve as proof.
Self-check
Prove
with explicit constants.
Is
?
Is
?
Explain from the definition.
Why is writing
conceptually clearer than
?
Distinguish worst-case, average-case, randomized expected, and
amortised cost.
Order
,
,
,
,
and
.
What is the bit length of a positive integer
,
asymptotically?
Why does every level of
contribute
non-recursive work?
Give an algorithm whose iterative and recursive forms have equal
time but different space costs.
Revision summary
Define input size, case, and cost model before counting.
Big O is an eventual upper bound, Omega a lower bound, and Theta a
tight bound.
Little-
and
little-
express strict asymptotic separation.
Common sums translate executions into growth functions.
Constants and lower-order terms vanish asymptotically but matter for
finite workloads.
Expected and amortised claims average over fundamentally different
things.
Time and auxiliary space require separate analyses.
Recurrence trees expose how recursive work is distributed across
levels.
Experiments test implementations; they do not prove asymptotic
results.
Implementations and
hands-on exploration
Python
timeit calibrates repetitions for short Python
statements and functions. Keep input construction outside the timed
statement when the algorithm alone is the object of study.
Google
Benchmark provides parameterised C++ microbenchmarks, fixtures,
counters, and repeated runs. Compiler optimisation and cache state can
still make a correct benchmark answer a narrower question than
intended.
Criterion.rs
performs warm-up, sampling, statistical analysis, and regression
comparisons for Rust. Statistical confidence concerns measured runs, not
an asymptotic proof or a guarantee on every input.
OpenJDK JMH provides a
harness for Java and other JVM microbenchmarks, with samples for
avoiding dead-code elimination and warm-up errors. Run its generated
benchmark project rather than treating an ordinary method timer as
equivalent.
Small experiments
Instrument the triangular nested loop. After outer iteration
,
assert the exact invariant count == i*(i+1)/2; for
,
also print count/n^2 and count/n. Which ratio
approaches a constant?
For powers of two, implement dummy work whose counters execute
exactly
and
operations. Assert both counts before timing the loops, then compare the
analytical and measured crossover points and explain any
difference.
Sources and further study
See the chapters on growth of functions and analysing algorithms in
Cormen et al.
(2022), and the introductory algorithm-analysis discussion in
Kleinberg and Tardos
(2006).
References
Cormen, Thomas H., Charles E. Leiserson, Ronald L. Rivest, and Clifford
Stein. 2022. Introduction to Algorithms. 4th ed. MIT Press.
Kleinberg, Jon, and Éva Tardos. 2006. Algorithm Design.
Pearson.