Meskipun @Marc telah memberikan (apa yang saya pikir) analisis yang sangat baik, beberapa orang mungkin lebih suka mempertimbangkan hal-hal dari sudut yang sedikit berbeda.
Pertama adalah mempertimbangkan cara yang sedikit berbeda dalam melakukan realokasi. Alih-alih segera menyalin semua elemen dari penyimpanan lama ke penyimpanan baru, pertimbangkan untuk menyalin hanya satu elemen pada satu waktu - yaitu, setiap kali Anda melakukan push_back, itu menambahkan elemen baru ke ruang baru, dan menyalin tepat satu yang sudah ada elemen dari ruang lama ke ruang baru. Dengan asumsi faktor pertumbuhan 2, cukup jelas bahwa ketika ruang baru penuh, kita akan selesai menyalin semua elemen dari ruang lama ke ruang baru, dan setiap push_back adalah waktu yang persis konstan. Pada saat itu, kami akan membuang ruang lama, mengalokasikan blok memori baru yang dua kali lebih besar, dan mengulangi prosesnya.
Cukup jelas, kita dapat melanjutkan ini tanpa batas waktu (atau selama masih ada memori tersedia) dan setiap push_back akan melibatkan penambahan satu elemen baru dan menyalin satu elemen lama.
Implementasi yang khas masih memiliki jumlah salinan yang persis sama - tetapi alih-alih melakukan salinan satu per satu, ia menyalin semua elemen yang ada sekaligus. Di satu sisi, Anda benar: itu berarti bahwa jika Anda melihat setiap doa push_back, beberapa di antaranya akan jauh lebih lambat daripada yang lain. Namun, jika kita melihat rata-rata jangka panjang, jumlah penyalinan yang dilakukan per permintaan push_back tetap konstan, terlepas dari ukuran vektor.
Meskipun tidak relevan dengan kompleksitas komputasi, saya pikir ada baiknya menunjukkan mengapa menguntungkan untuk melakukan hal-hal seperti yang mereka lakukan, daripada menyalin satu elemen per push_back, sehingga waktu per push_back tetap konstan. Setidaknya ada tiga alasan untuk dipertimbangkan.
Yang pertama adalah ketersediaan memori. Memori lama dapat dibebaskan untuk penggunaan lain hanya setelah penyalinan selesai. Jika Anda hanya menyalin satu item pada suatu waktu, blok memori lama akan tetap dialokasikan lebih lama. Bahkan, Anda akan memiliki satu blok lama dan satu blok baru yang pada dasarnya dialokasikan setiap saat. Jika Anda memutuskan faktor pertumbuhan yang lebih kecil dari dua (yang biasanya Anda inginkan), Anda akan membutuhkan lebih banyak memori yang dialokasikan setiap saat.
Kedua, jika Anda hanya menyalin satu elemen lama pada satu waktu, pengindeksan ke dalam array akan sedikit lebih rumit - setiap operasi pengindeksan perlu mencari tahu apakah elemen pada indeks yang diberikan saat ini berada di blok memori lama atau baru. Itu tidak terlalu rumit dengan cara apa pun, tetapi untuk operasi dasar seperti pengindeksan ke dalam array, hampir semua pelambatan bisa menjadi signifikan.
Ketiga, dengan menyalin sekaligus, Anda memanfaatkan caching dengan lebih baik. Menyalin sekaligus, Anda dapat mengharapkan sumber dan tujuan berada di cache dalam banyak kasus, sehingga biaya dari cache yang ketinggalan diamortisasi selama jumlah elemen yang sesuai dengan garis cache. Jika Anda menyalin satu elemen pada satu waktu, Anda mungkin dengan mudah kehilangan cache untuk setiap elemen yang Anda salin. Itu hanya mengubah faktor konstan, bukan kompleksitas, tetapi masih bisa cukup signifikan - untuk mesin biasa, Anda dapat dengan mudah mengharapkan faktor 10 hingga 20.
Mungkin juga patut mempertimbangkan arah lain sejenak: jika Anda mendesain sistem dengan persyaratan waktu nyata, mungkin lebih baik untuk menyalin hanya satu elemen pada satu waktu alih-alih sekaligus. Meskipun kecepatan keseluruhan mungkin (atau mungkin tidak) lebih rendah, Anda masih memiliki batas atas yang sulit pada waktu yang dibutuhkan untuk satu eksekusi push_back - anggap Anda memiliki pengalokasi waktu nyata (meskipun tentu saja, banyak waktu nyata sistem hanya melarang alokasi memori dinamis sama sekali, setidaknya sebagian dengan persyaratan waktu nyata).