Amortized Analysis
Three ways to show that an occasionally expensive operation is cheap on average: aggregate, accounting and potential.
Lessons in this course
Foundations
01Growth Rates and Big O- 02Recurrences and the Master Theorem
Going further
03Amortized Analysis
The problem with worst cases
Appending to a dynamic array is usually one write. Occasionally the array is full and the append has to allocate a bigger block and copy everything across, which costs . A plain worst-case analysis says appends at each, so . That bound is true and badly pessimistic: the expensive appends are rare, and each one buys a long run of cheap ones.
Amortized analysis bounds the total cost of any sequence of operations and divides by . No probability is involved: it is a worst-case guarantee for the sequence rather than for a single call.
- Dynamic array. Empty, with capacity 0. The first append allocates one slot. After that, an append to a full array doubles the capacity and copies every element. A write or a copy costs 1.
- Binary counter. bits, starting at zero. Incrementing flips trailing 1s to 0, then flips one 0 to 1. A flip costs 1.
def increment(bits):
"""bits[0] is the least significant bit."""
i = 0
while i < len(bits) and bits[i] == 1:
bits[i] = 0
i += 1
if i < len(bits):
bits[i] = 1Aggregate method
Add up the real cost of the whole sequence.
Array. appends make writes. Copies happen at sizes below , and a copy at size costs , so
An append therefore costs below 3 amortized, which is .
Counter. Bit flips on every -th increment, so over increments the flips total
and an increment costs less than 2 amortized, even though a single one can flip all bits.
Accounting method
Charge each operation a fixed amortized price. When the price exceeds the real cost, bank the difference as credit on the data structure; when an operation is expensive, pay from the bank. The analysis is valid as long as the balance never goes negative.
Array. Charge 3 per append: one unit pays for the write, two are stored on the new element. When an array of capacity fills up, the elements added since the last resize hold units between them, exactly enough to copy all elements.
Counter. Charge 2 per increment. One unit pays for setting a bit to 1 and the other stays on that bit to pay for clearing it later. Each increment sets at most one bit, so every 1 in the counter carries the unit needed to reset it, and resets are free.
Potential method
Instead of crediting individual elements, describe the bank balance as a function of the whole state. A potential function maps each state to a number, with and for all . The amortized cost of operation is defined as
Summed over the sequence, the potentials telescope:
so the total amortized cost bounds the total real cost from above.
Array. Take . The empty array has , and because an append-only array is always at least half full once the first slot exists, throughout. Two cases.
No resize. The real cost is 1. The size grows by one and the capacity is unchanged, so rises by 2:
Resize. Before the append, , so . Afterwards and , so . The real cost is copies plus one write:
The potential climbs by 2 on every cheap append and stands at exactly when a copy of elements falls due, so the expensive operation is paid for by the drop in potential. (The first append, from capacity 0 to 1, costs only 2.)
Counter. Take to be the number of 1 bits. If an increment clears bits, its real cost is at most and the potential changes by at most , so .
Exercises
1. Suppose the array grows by a fixed 100 slots instead of doubling. What is the amortized cost of an append?
Show the solution
Resizes happen every 100 appends and copy elements, so the copies over appends total
The amortized cost per append is . Growth has to be geometric for the cheap appends to pay for the expensive ones.
2. A queue is built from two stacks. enqueue pushes onto inbox. dequeue pops from outbox, but if outbox is empty it first pops every element from inbox and pushes it onto outbox. With each push and pop costing 1, use a potential function to show that both operations are amortized.
Show the solution
Let . It starts at 0 and is never negative.
enqueue: real cost 1, rises by 2, amortized cost 3.dequeuewithout a transfer: real cost 1, unchanged, amortized cost 1.dequeuewith a transfer of elements: real cost , falls by , amortized cost 1.
3. Add a decrement operation to the binary counter. Show that a sequence of operations can now cost .
Show the solution
Bring the counter to , which is . An increment flips all bits to give , and a decrement flips them all back. Alternating the two costs per operation indefinitely. The potential argument breaks because a decrement can raise the number of 1 bits by without paying for it. An amortized bound belongs to a set of operations, not to a data structure alone.
That is the end of Algorithm Analysis Essentials. Back to the course.