gấp đôi để khi bạn push_back n lần, bạn chỉ phải xóa mảng cũ tạo mảng mới khoảng log(n) lần thôi, và gán/copy các phần tử khoảng 3n lần. (nếu mảng có dung lượng vô hạn thì n lần push_back() tốn n lần copy/gán phần tử)
ví dụ mảng ban đầu có 0 phần tử. Bạn push_back() 9 lần
lần 1: tạo mảng mới 1 phần tử, copy 1 lần
lần 2: xóa mảng cũ tạo mảng mới, copy mảng cũ sang mảng mới mất 1 lần copy, thêm phần tử mới vào mất 1 lần copy nữa là 2 lần. Dung lượng mảng hiện tại là 2.
lần 3: xóa mảng cũ tạo mảng mới. Tốn 3 lần copy. Dung lượng mảng hiện tại là 4.
lần 4: vì dung lượng mảng hiện tại là 4 đủ chỗ, nên chỉ cần thêm phần tử mới vào. 1 lần copy
lần 5: xóa mảng cũ tạo mảng mới. Tốn 4+1 = 5 lần copy. Dung lượng mảng hiện tại là 8.
lần 6, 7, 8: chỉ cần 1 lần copy vì đủ chỗ chứa.
lần 9: xóa mảng cũ tạo mảng mới. Tốn 8+1 = 9 lần copy. Dung lượng mảng hiện tại là 16.
tổng cộng 9 lần push_back() bạn phải copy 1 + 2 + 3 + 1 + 5 + 1 + 1 + 1 + 9 = 24 lần copy ~ 3n-3 lần copy.
bạn làm thử với 16 lần, 17 lần push_back nữa sẽ thấy nó ko bao giờ vượt quá 3n lần copy, như vậy “trung bình” mỗi lần push_back() chỉ tốn 3 lần copy, hay là O(1) lần copy. Nếu bạn chỉ tăng dung lượng lên vd 1 đơn vị cho đủ chỗ chứa, thì mỗi lần push_back() phải copy cả mảng cũ rồi tạo mảng mới, như vậy là O(n) lần copy…
cái này gọi là amortized analysis gì đó, có cái dễ có cái khó…
ngồi tính công thức tổng quát cho n lần push_back luôn cũng được:
1 + 2 + 3 + 1 + 5 + 1 + 1 + 1 + 9 + …
1 + (1+1) + (1+2) + 1 + (1+4) + 1 + 1 + 1 + (1+8) + …
= 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + … + 1 + (1 + 2 + 4 + 8 + … + 2k)
= n + [2k+1 - 1]
= n + [2(2k) - 1]
= n + [2(n-1) - 1]
= 3n - 3
với n = 2k + 1 cho lần push_back() cuối cùng là hao nhất.
bạn ngồi tính nếu tăng 3 lần thay vì 2 lần nó có giảm nhỏ hơn 3n-3 ko. Đáp án là có, nhưng tăng 3 lần thì quá tốn bộ nhớ nên người ta tăng 2 thôi. Nếu tăng 1.5 lần thì hằng số c trong cn
sẽ lớn hơn 3, tức là “trung bình” 1 lần push_back() sẽ lâu hơn, nhưng tiết kiệm bộ nhớ hơn. Người ta để 2 cho “cân bằng”.