🎯 Objective: let an ArrayList exceed capacity ➔ allocate a bigger array, copy across, replace, insert.
📦 Core Components: grow by a constant factor ➔ append is O(1) amortised (so no is_full).
⚡ Key Constraint: a single append can be O(N) (resize copy), but factor growth makes the sequence O(1) each; additive growth fails (Θ(n2)).
📝 Core
1. The Resize (Allocate → Copy → Replace → Insert)
On overflow ➔ allocate a bigger array ➔ copy all elements ➔ replace (old → garbage) ➔ insert.
Factor growth ➔ constant-factor resize makes appendO(1) amortised ➔ why the List (ADT) has no is_full.
2. The Growth Factor (Space–Time Dial)
Doubling (×2) ➔ few resizes, up to 2× slack, each new block exceeds sum of all previous (no allocator reuse).
×1.5 (CPython ~1.125+const) ➔ less slack, freed blocks reusable, more copies.
Shrinking ➔ needs hysteresis (halve only at ¼ full) to avoid O(n) thrashing at a boundary.
⚙️ Core Implementation
🔹 Grow-on-overflow append
resize + insert
def append(self, item): if len(self) == len(self.array): # full -> resize new_array = ArrayR(self.__newsize()) # newsize = old * factor for i in range(len(self)): # copy: O(N) new_array[i] = self.array[i] self.array = new_array self.array[len(self)] = item; self.length += 1
💡 Common Mistake:Growth must be multiplicative ➔ a constant additive (+k) growth makes n appends Θ(n2); the multiplicative factor is exactly what makes resizes geometrically rare.
⚖️ Core Decision Matrix
Situation
append
Why
room available
O(1)
write + increment
full (resize)
O(N)
allocate + copy N
amortised
O(1)
factor growth spreads rare copies
When It Flips: three proofs of amortised O(1) (doubling) — Aggregate: copies cost 1+2+4+⋯+n<2n ⟹ O(1) each. Accounting: charge 3 credits/append (1 write + 2 banked); never negative. Potential:Φ=2⋅len−capacity; normal append amortised 1+ΔΦ=3, resize's O(n) copy cancelled by the drop in Φ. Same argument powers Hash Table rehashing; amortised ≠ average — a worst-case-sequence guarantee with no probability.