Algorithm Search⌘K

Proofs: Dynamic array

These are the human proofs of Dynamic array, at full length.

Append and pop on a dynamic array cost O(1) amortized full

This proof shows: amortized.

Cost model. APPEND costs 1 for line L2, plus nn if line L1 resizes. POP costs 1 for line L5, plus n′n' if line L6 resizes, where n′=n−1n' = n - 1 is the count after line L4. RESIZE costs one unit per copy in line L10. GET and SET cost 1 and do not change nn or capcap.

Potential. For a state with count nn and capacity capcap, let

Φ(n,cap)={2n−capif 2n≥cap,cap/2−nif 2n<cap.\Phi(n, cap) = \begin{cases} 2n - cap & \text{if } 2n \ge cap, \\ cap/2 - n & \text{if } 2n < cap. \end{cases}

Both branches are at least 0 where they apply, so Φ≥0\Phi \ge 0. At the start Φ(0,1)=1/2\Phi(0, 1) = 1/2. The amortized cost of an operation is its cost plus Φafter−Φbefore\Phi_{\text{after}} - \Phi_{\text{before}}.

Claim. Each APPEND has amortized cost at most 3, and each POP at most 2.

APPEND without a resize (n<capn < cap). The cost is 1 and nn becomes n+1n + 1.

  • If 2n≥cap2n \ge cap: ΔΦ=2(n+1)−2n=2\Delta\Phi = 2(n + 1) - 2n = 2, amortized cost 3.
  • If 2(n+1)<cap2(n + 1) < cap: ΔΦ=−1\Delta\Phi = -1, amortized cost 0.
  • If 2n<cap≤2n+22n < cap \le 2n + 2: ΔΦ=(2n+2−cap)−(cap/2−n)=3n+2−32cap\Delta\Phi = (2n + 2 - cap) - (cap/2 - n) = 3n + 2 - \tfrac{3}{2} cap. Since cap>2ncap > 2n, this is less than 3n+2−3n=23n + 2 - 3n = 2, so the amortized cost is less than 3.

APPEND with a resize (n=cap≥1n = cap \ge 1). The cost is 1+n1 + n. Before, Φ=2n−n=n\Phi = 2n - n = n. After, the count is n+1n + 1 and the capacity 2n2n, and 2(n+1)≥2n2(n + 1) \ge 2n, so Φ=2(n+1)−2n=2\Phi = 2(n + 1) - 2n = 2. The amortized cost is 1+n+2−n=31 + n + 2 - n = 3.

POP without a resize. The cost is 1 and nn becomes n′=n−1n' = n - 1, with the same capcap.

  • If 2n′≥cap2n' \ge cap: ΔΦ=−2\Delta\Phi = -2, amortized cost −1-1.
  • If 2n<cap2n < cap: ΔΦ=(cap/2−n+1)−(cap/2−n)=1\Delta\Phi = (cap/2 - n + 1) - (cap/2 - n) = 1, amortized cost 2.
  • If 2n′<cap≤2n2n' < cap \le 2n: ΔΦ=(cap/2−n+1)−(2n−cap)=32cap−3n+1\Delta\Phi = (cap/2 - n + 1) - (2n - cap) = \tfrac{3}{2} cap - 3n + 1. Since cap≤2ncap \le 2n, this is at most 3n−3n+1=13n - 3n + 1 = 1, so the amortized cost is at most 2.

POP with a resize (n′≥1n' \ge 1 and cap=4n′cap = 4n'). The cost is 1+n′1 + n'. After, the capacity is 2n′2n' and the count n′n', so Φ=2n′−2n′=0\Phi = 2n' - 2n' = 0. Before, the count was n′+1n' + 1.

  • If n′≥2n' \ge 2: 2(n′+1)<4n′2(n' + 1) < 4n', so Φbefore=2n′−(n′+1)=n′−1\Phi_{\text{before}} = 2n' - (n' + 1) = n' - 1, and the amortized cost is 1+n′+0−(n′−1)=21 + n' + 0 - (n' - 1) = 2.
  • If n′=1n' = 1: cap=4cap = 4 and the count was 2, so 2⋅2≥42 \cdot 2 \ge 4 and Φbefore=0\Phi_{\text{before}} = 0. The amortized cost is 1+1+0−0=21 + 1 + 0 - 0 = 2.

This proves the claim. □\square

Theorem. Any sequence of mm operations on a new dynamic array, of which aa are appends, costs at most 3a+2(m−a)+1/2≤3m+1/23a + 2(m - a) + 1/2 \le 3m + 1/2.

Proof. Let ckc_k and c^k\hat c_k be the cost and the amortized cost of operation kk, and Φk\Phi_k the potential after it. Then ∑k=1mc^k=∑k=1mck+Φm−Φ0\sum_{k=1}^{m} \hat c_k = \sum_{k=1}^{m} c_k + \Phi_m - \Phi_0, because the sum of the differences telescopes. So ∑ck=∑c^k−Φm+Φ0≤∑c^k+1/2\sum c_k = \sum \hat c_k - \Phi_m + \Phi_0 \le \sum \hat c_k + 1/2, because Φm≥0\Phi_m \ge 0 and Φ0=1/2\Phi_0 = 1/2. GET and SET have amortized cost 1, and the claim bounds the rest. ■\blacksquare

The dynamic array keeps its list and its size bound full

This proof shows: correctness.

Invariant. (I1) 0≤n≤cap0 \le n \le cap, and the list held is (A[0],…,A[n−1])(A[0], \ldots, A[n-1]). (I2) cap=2ecap = 2^e for some integer e≥0e \ge 0, and cap<4max⁡(n,1)cap < 4 \max(n, 1).

At the start n=0n = 0 and cap=1=20<4cap = 1 = 2^0 < 4, so both parts hold for the empty list.

Lemma (RESIZE). If n≤cn \le c, then RESIZE(D,c)(D, c) leaves nn unchanged, sets cap=ccap = c, and leaves the list (A[0],…,A[n−1])(A[0], \ldots, A[n-1]) unchanged.

Proof. Line L8 makes a block BB of cc cells. The loop of lines L9 and L10 keeps the invariant "B[k]=A[k]B[k] = A[k] for 0≤k<i0 \le k < i" at its test with value ii: it holds for i=0i = 0, and line L10 extends it to i+1i + 1. It runs for i=0,…,n−1i = 0, \ldots, n - 1, and each index is less than cc because n≤cn \le c. At exit B[0…n−1]=A[0…n−1]B[0 \ldots n-1] = A[0 \ldots n-1]. Line L11 makes BB the block and sets cap=ccap = c. □\square

APPEND(D,x)(D, x). Let (ℓ0,…,ℓn−1)(\ell_0, \ldots, \ell_{n-1}) be the list before the call, and assume (I1) and (I2).

  • If n<capn < cap, line L1 does nothing. Line L2 writes xx to cell n<capn < cap, and line L3 sets the count to n+1≤capn + 1 \le cap. The list is (ℓ0,…,ℓn−1,x)(\ell_0, \ldots, \ell_{n-1}, x). The capacity is the same power of two, and cap<4max⁡(n,1)≤4(n+1)cap < 4\max(n, 1) \le 4(n + 1).
  • If n=capn = cap, line L1 calls RESIZE(D,2cap)(D, 2 cap), with n≤2capn \le 2 cap, so by the lemma the list is unchanged and capcap becomes 2n=2e+12n = 2^{e+1}. Now n<capn < cap because n=cap/2n = cap/2 and cap≥2cap \ge 2. Lines L2 and L3 append xx as in the first case. After the call, n+1≤2n=capn + 1 \le 2n = cap because n=2e≥1n = 2^e \ge 1, and cap=2n<4(n+1)cap = 2n < 4(n + 1).

In both cases (I1) and (I2) hold for the list with xx appended.

POP(D)(D), n≥1n \ge 1. Let (ℓ0,…,ℓn−1)(\ell_0, \ldots, \ell_{n-1}) be the list. Line L4 sets the count to n′=n−1n' = n - 1, and line L5 reads x=A[n′]=ℓn−1x = A[n'] = \ell_{n-1}, which is in range because n′<n≤capn' < n \le cap. The list A[0…n′−1]A[0 \ldots n'-1] is (ℓ0,…,ℓn−2)(\ell_0, \ldots, \ell_{n-2}), and (I1) holds. Line L7 returns ℓn−1\ell_{n-1}, the last item. It remains to show (I2) after line L6. Before the call, cap<4max⁡(n,1)=4n=4n′+4cap < 4\max(n, 1) = 4n = 4n' + 4.

  • Case n′=0n' = 0. Line L6 does nothing. Then cap<4=4max⁡(n′,1)cap < 4 = 4\max(n', 1).
  • Case n′≥1n' \ge 1 and 4n′=cap4n' = cap. Line L6 calls RESIZE(D,cap/2)(D, cap/2). Here cap=4n′≥4cap = 4n' \ge 4, so cap/2=2e−1cap/2 = 2^{e-1} is a power of two and is at least 2n′≥n′2n' \ge n'. By the lemma the list is unchanged, and the new capacity is 2n′<4n′2n' < 4n'.
  • Case n′≥1n' \ge 1 and 4n′≠cap4n' \ne cap. Line L6 does nothing. If cap≤3cap \le 3, then cap<4≤4n′cap < 4 \le 4n'. If cap≥4cap \ge 4, then capcap is a multiple of 4, and cap<4n′+4cap < 4n' + 4 gives cap≤4n′cap \le 4n'; with cap≠4n′cap \ne 4n' this gives cap<4n′cap < 4n'.

In all cases (I2) holds with n′n'.

GET and SET. These read or write A[i]A[i] for 0≤i<n0 \le i < n, as in an array, and change neither nn nor capcap. ■\blacksquare

Back to Dynamic array