Amortized analysis
◈ 5 cardsWorst-case-average over a sequence (not probability); aggregate / accounting / potential; the dynamic-table doubling result.
Averaging cost over a sequence — with no probability
Amortized analysis bounds the average cost per operation over a worst-case sequence of operations. It shows that even if one operation is occasionally expensive, the average over the whole sequence is small. The critical distinction the exam tests:
> Amortized analysis involves no probability and no distribution. It is a worst-case guarantee on the average cost per operation — not an average-case (expected) analysis.
If any sequence of operations costs at most , the amortized cost per operation is , and that holds for every sequence, not just typical ones.
The three methods
- Aggregate — bound the total cost of the whole sequence directly, then charge to every operation equally.
- Accounting — assign each operation a (possibly different) amortized charge ; overcharges bank credit on data-structure objects, undercharges spend it. Valid as long as total credit stays , i.e. .
- Potential — define a potential on the data-structure state; the amortized cost is . By telescoping, , so if the amortized total upper-bounds the actual total.
All three give upper bounds on the same real cost; they only differ in bookkeeping. Pick whichever is most natural.
Warm-ups: the stack with MULTIPOP and the binary counter
MULTIPOP(S, k) pops items — a single call is , so a naive bound on operations is . But aggregate analysis nails it: each object is pushed at most once and popped at most once, so across the whole sequence there are at most pops total. Total cost , amortized . The accounting view: charge $\$2$ at each PUSH ($\$1$ to push now, $\$1$ of credit on the object for its eventual pop); then POP and MULTIPOP are $\$0$ amortized. The potential view: $\Phi = $ stack size — PUSH is $1 + 1 = 2$, MULTIPOP of $k'$ items is $k' - k' = 0$.
The -bit binary counter: INCREMENT flips every time, every other time, every fourth time, … So total flips over increments . Amortized per INCREMENT.
The headline result: dynamic-table doubling
A dynamic table (Python list, Java ArrayList, C++ vector) grows by doubling when it fills. A TABLE-INSERT that triggers a resize costs (copy everything to a bigger array); a non-resizing insert costs . Naive bound: . But resizes happen at sizes , so the total copy cost over inserts is (a geometric series). Total work , so insertion is amortized despite occasional resizes. (Contraction needs care: halving at rather than avoids thrashing, where alternating insert/delete triggers a resize every step.)
Worked example — count the copies, see the geometric series
Do appends into a table that starts at capacity 1 and doubles when full. The capacity passes through , and each doubling copies the existing elements: total copies for 16 appends. That is copies per append — less than one copy each on average, even though the single resize from 8 to 16 alone copied 8 elements. The expensive resizes are exactly cancelled by the cheap inserts between them: amortized, demonstrated, not just asserted.