Week 5, Tuesday (Video)
February 3, 2026
The mystery: Arrays have fixed size in memory. How does append work when the array is “full”?
What if we allocated exactly the space we need?
Key insight: Don’t resize every time. Resize strategically.
Two strategies to consider:
Which is better?
Starting with capacity 2:
Let \(n = 2^k\) for some \(k\) (makes counting easier).
Resizes happen at sizes 2, 4, 6, 8, …, \(n\).
That’s \(n/2\) resize events, copying \(2 + 4 + 6 + \ldots + n\) items.
\[2 + 4 + 6 + \ldots + n = 2(1 + 2 + 3 + \ldots + n/2) = 2 \cdot \frac{(n/2)(n/2 + 1)}{2}\]
\[= \frac{n}{2} \cdot \frac{n+2}{2} = \frac{n^2 + 2n}{4} = O(n^2)\]
Verdict: \(O(n^2)\) total copies, or \(O(n)\) per append on average.
Starting with capacity 1:
Again, let \(n = 2^k\).
Resizes happen when we fill capacities 1, 2, 4, 8, …, \(n/2\).
That’s \(k\) resize events (at capacities \(2^0, 2^1, \ldots, 2^{k-1}\)).
Total copies: \(1 + 2 + 4 + 8 + \ldots + n/2\)
This is a geometric series!
\[1 + 2 + 4 + \ldots + 2^{k-1} = 2^k - 1 = n - 1 = O(n)\]
Verdict: \(O(n)\) total copies, or \(O(1)\) per append on average!
| Strategy | Total work for n appends | Average per append |
|---|---|---|
| Add constant k | \(O(n^2)\) | \(O(n)\) |
| Double | \(O(n)\) | \(O(1)\) |
Doubling wins! This is why Python lists (and Java ArrayLists, C++ vectors) all use doubling.
I think I would have 2 questions…
Amortized = “averaged over a sequence of operations”
Individual appends have different costs:
But averaged over \(n\) operations: \(O(1)\) each!
Think of it like a savings account:
When we double from size \(n\) to \(2n\):
Average case: Random inputs, expected behavior
Amortized: Worst case, but spread over many operations
Amortized O(1) is a guarantee:
“Any sequence of n operations takes O(n) time total.”
You’ll see the size jump at certain points (the doublings!).
Doubling pros:
Doubling cons:
For most applications, the speed is worth the space.
Same analysis works for:
The doubling trick is everywhere!
Arrays are fixed size — growing requires copying
Add-constant strategy: \(O(n^2)\) for n appends (bad!)
Doubling strategy: \(O(n)\) for n appends (good!)
Amortized O(1): Expensive operations are rare enough to average out
This is how Python lists work!
Wednesday: Back to stacks and queues — exploring mazes with DFS and BFS!