class ArrayList:
def __init__(self, capacity = 10):
self._capacity = capacity
self._arr = [0]*capacity # Have an array in the background, and I'm only allowed to
# make a new array of a fixed length, or to modify the current array's elements
self._N = 0 # How many elements we have
def add_fast(self, x):
"""
Add an element at the end of the list, doubling
capacity if needed
(NOTE: We could do more work to share between add_slow)
Parameters
----------
x: The element to add
"""
if self._N == self._capacity:
self._capacity *= 2
new_arr = [0]*self._capacity
for i in range(self._N):
new_arr[i] = self._arr[i]
self._arr = new_arr
# Now I know I have enough room no matter what
self._arr[self._N] = x
self._N += 1
def __len__(self):
return self._N
Consider adding N elements. Furthermore, let's suppose that when we add the Nth element, we double right at that moment. This is really the worst case, because we just spent all of this time doubling the capacity, but then we walked away
The total time to add N elements, T(N) consists of two parts:
self._arr[self._N] = x
self._N += 1
Suppose that these operations take some constant a
Overall, this contributes a total of Ta(N)=aN to the total cost
Let's work backwards to figure out how much we have to pay over all of the doublings
The last doubling happened at N, so we doubled up to 2N, which took b2N
Second to last doubling, doubled to a size of N, took bN
Third to last doubling, double to a size of N/2, took bN/2
...
Total contribution over all doublings is
Td(N)=2bN+bN+bN/2+bN/4+...+n0 (n0 initial capacity)
Td(N)≤2bN(1+1/2+1/4+1/8+...+0)
We can use the identity that
1 + 1/2 + 1/4 + 1/8 + ... 0 = 2. Therefore
Td(N)≤2bN∗2
Td(N)≤4bN
Total time T(N)=Ta(N)+Td(N)≤aN+4bN
T(N)≤(a+4b)N
Let c=a+4b
T(N)≤cN⟹T(N) is O(N)
Amortized (Average) cost T(N)/N is c, which is O(1)