Menu

Algoritma STL C++: Panduan Praktis dengan Contoh

Pakai algoritma standar C++ seperti find, count_if, transform, accumulate, dan remove untuk mengolah range tanpa menulis loop sendiri, plus jebakan pasangan iterator dan erase-remove.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Loop yang Tidak Perlu Kamu Tulis

Di halaman sebelumnya kamu melihat bahwa setiap container menyediakan iterator, yaitu kursor ringan dengan begin() dan end(). Abstraksi itulah alasan algoritma standar ada. Daripada menulis for loop mentah setiap kali ingin mencari, menghitung, atau mengubah data, kamu cukup memanggil fungsi bernama dari <algorithm> dan memberinya sebuah range.

Range hanyalah dua iterator: tempat mulai, dan satu posisi setelah tempat berhenti. Karena setiap algoritma memakai bahasa iterator yang sama, find yang sama bisa dipakai pada vector, string, atau array biasa.

Pola yang perlu kamu ingat: algoritma pencarian mengembalikan iterator end() untuk menyatakan "tidak ada yang ditemukan". Selalu bandingkan dengan end() sebelum melakukan dereference pada hasilnya, karena dereference pada end() adalah undefined behavior.

Menghitung dan Menguji dengan Predicate

Banyak algoritma menerima predicate, yaitu fungsi (biasanya lambda) yang mengembalikan bool untuk setiap elemen. count_if menghitung elemen yang cocok; all_of, any_of, dan none_of menjawab pertanyaan ya/tidak tentang seluruh range.

std::count (tanpa _if) adalah versi yang lebih sederhana, yang menghitung nilai yang persis alih-alih kondisi. Gunakan versi predicate begitu yang kamu uji adalah "apa saja yang memenuhi aturan", bukan "nilai yang ini".

Mengubah dan Meringkas Range

Dua andalan ini mencakup sebagian besar pengolahan data: std::transform memetakan setiap elemen lewat sebuah fungsi, dan std::accumulate (dari <numeric>, bukan <algorithm>) meringkas sebuah range menjadi satu nilai.

transform menulis hasilnya lewat output iterator. Kesalahan yang umum dan berbahaya adalah mengarahkan output ke vector kosong: algoritma menganggap ruangnya sudah tersedia dan menulis melewati ujungnya. Atur dulu ukuran tujuannya, atau pakai back_inserter supaya setiap hasil di-push_back.

accumulate dimulai dari sebuah nilai awal lalu menggabungkan elemen dari kiri ke kanan. Tipe nilai awal itu penting: berikan 0 (sebuah int) dan jumlahnya dihitung dalam int, yang bisa overflow atau terpotong tergantung tipe data elemennya.

Seandainya kamu menulis accumulate(prices.begin(), prices.end(), 0) dengan nilai awal int, setiap penjumlahan terjadi dalam int dan angka sen-nya hilang. Tipe nilai awal diam-diam menentukan tipe hasilnya.

Idiom Erase-Remove

Inilah jebakan yang mengejutkan semua orang. std::remove tidak menghapus apa pun dari container. Algoritma hanya memegang iterator, jadi mereka tidak bisa mengubah ukuran container; mereka bahkan tidak tahu ada container di sana. Yang sebenarnya dilakukan remove adalah memindahkan semua elemen yang dipertahankan ke depan, membiarkan bagian ekornya dalam keadaan yang tidak ditentukan, lalu mengembalikan iterator ke ujung logis yang baru.

// remove alone leaves the size unchanged - this is the bug:
remove(v.begin(), v.end(), 0);  // returns an iterator you ignored
// v still has its original size; the tail is garbage

Untuk benar-benar menghapus elemen, kamu memasangkan remove dengan erase milik container. Karena itulah namanya idiom erase-remove:

Pakai remove_if untuk predicate alih-alih nilai yang persis. Di C++20 kamu bisa melewati semua langkah ini dengan fungsi bebas std::erase / std::erase_if, yang mengerjakan kedua langkah sekaligus: erase(v, 0);.

Iterator yang Dipakai Melewati Masa Berlakunya Berbahaya

Karena algoritma mengembalikan iterator, iterator itu tunduk pada aturan invalidasi yang sama seperti di halaman sebelumnya. Menyimpan iterator lalu mengubah container (misalnya push_back yang memicu realokasi, atau erase) bisa membuat iterator yang tersimpan menjadi dangling, dan memakainya adalah undefined behavior.

auto it = find(v.begin(), v.end(), 16);
v.push_back(99);   // may reallocate v's storage
cout << *it;       // BUG: `it` may now point at freed memory

Kebiasaan yang aman: pakai iterator yang dikembalikan algoritma segera, sebelum operasi apa pun yang bisa mengubah ukuran atau merealokasi container. Kalau kamu perlu mengubah container berdasarkan sebuah hasil, simpan indeks-nya (it - v.begin()), karena indeks tetap berlaku setelah realokasi.

Berikutnya: Sorting

Sekarang kamu sudah melihat pencarian, penghitungan, pengubahan, dan peringkasan. Namun ada satu algoritma yang cukup penting sampai layak punya halaman sendiri. std::sort mengurutkan ulang sebuah range di tempat, dan begitu data terurut, terbukalah satu keluarga algoritma yang lebih cepat dan khusus untuk data terurut (binary_search, lower_bound, equal_range). Berikutnya kita akan mendalami sorting: cara memberikan comparator sendiri, perbedaan antara sort dan stable_sort, dan aturan yang harus dipatuhi fungsi pembandingmu agar terhindar dari undefined behavior.

Pertanyaan yang sering diajukan

Apa itu header <algorithm> di C++?

<algorithm> adalah header standard library yang berisi fungsi generik seperti std::find, std::sort, std::count_if, dan std::transform. Fungsi-fungsi ini bekerja pada range yang ditentukan oleh sepasang iterator (biasanya begin() dan end()), jadi algoritma yang sama bisa dipakai pada vector, array, string, atau container apa pun yang menyediakan iterator.

Bagaimana cara mengecek apakah sebuah nilai ada di vector C++?

Pakai std::find: auto it = find(v.begin(), v.end(), target);. Kalau it == v.end(), nilainya tidak ada; kalau tidak, it menunjuk ke kecocokan pertama. Untuk menguji sebuah kondisi alih-alih nilai yang persis, pakai std::any_of dengan sebuah predicate.

Kenapa std::remove tidak benar-benar menghapus elemen dari container-ku?

Algoritma hanya melihat iterator, bukan container-nya, jadi std::remove tidak bisa mengecilkan container. Ia memindahkan elemen yang dipertahankan ke depan dan mengembalikan iterator ke ujung logis yang baru. Kamu harus menyusulnya dengan v.erase(...) (idiom erase-remove) agar sisanya benar-benar dibuang.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai