03Module · Goodrich Ch. 3
Week 3 — Algorithm Analysis
The seven core functions, asymptotic Big-Oh / Omega / Theta notation, justification techniques, and loop invariants.
Algorithm Analysis
Measuring algorithm efficiency by how cost grows with input size, and proving bounds with induction and invariants.
Theory
Experimental measurement is necessary but insufficient: results depend on hardware and inputs. Asymptotic analysis abstracts these away.
Big-O is an upper bound, Big-Omega a lower bound, and Big-Theta a tight bound on a function's growth rate.
The seven canonical functions: constant, logarithmic, linear, n log n, quadratic, cubic, exponential.
Correctness proofs use loop invariants (initialization, maintenance, termination) and induction on input size.
Key points
- Drop constants and lower-order terms: 3n² + 100n + 5 is Θ(n²).
- log n grows slower than nᵉ for any ε > 0.
- Amortized analysis bounds the average cost of a sequence of operations.
Code examples
Three algorithms for prefix averages
Three algorithms for prefix averages
# O(n^2) — recompute each prefix sum
def prefix_avg_quadratic(s):
n = len(s)
a = [0] * n
for j in range(n):
a[j] = sum(s[: j + 1]) / (j + 1)
return a
# O(n) — running total
def prefix_avg_linear(s):
n = len(s)
a, total = [0] * n, 0
for j in range(n):
total += s[j]
a[j] = total / (j + 1)
return aLoop invariant — find max
Loop invariant — find max
def find_max(a):
# Invariant: best is the max of a[0:i]
best = a[0]
for i in range(1, len(a)):
if a[i] > best:
best = a[i]
# Termination: i = len(a), so best = max(a[0:len(a)])
return best