Algoritma STL tidak menerima container sebagai argumen; ia menerima pasangan iterator yang menggambarkan rentang (range) elemen: first sebagai awal dan last sebagai batas akhir. Konvensi ini yang membuat satu algoritma bisa bekerja pada seluruh vector, sebagian vector, array C-style, bahkan hasil beberapa container yang digabungkan. Rentangnya selalu setengah terbuka, ditulis [first, last): elemen yang ditunjuk first ikut diproses, elemen yang ditunjuk last tidak. Pada Chapter ini kita membedah makna konvensi tersebut, pola pemanggilan algoritma yang berulang-ulang, dan sekilas melihat gaya baru std::ranges:: dari C++20.
Makna Rentang Setengah Terbuka [first, last) #
Notasi [first, last) terlihat sepele, tetapi menyimpan tiga konsekuensi desain yang menjelaskan banyak perilaku STL. Pertama, rentang kosong dinyatakan dengan satu kondisi: first == last. Tidak perlu penanganan khusus saat data nol elemen. Kedua, jumlah elemen dihitung dengan last - first pada iterator random access — tanpa penyesuaian satu-dua-tiga. Ketiga, last boleh menunjuk posisi setelah elemen terakhir (end()), sehingga rentang “seluruh container” ditulis rapi sebagai [begin, end).
Karena itu pula aturan keamanannya jelas: last harus tercapai dengan maju dari first, dan last sendiri tidak boleh didereference. Algoritma menghentikan proses tepat ketika mencapai last, sehingga selama kedua iterator itu sah, tidak ada akses di luar batas.
Pola Pemakaian Algoritma #
Semua algoritma di header <algorithm> mengikuti pola yang mudah dikenali: nama algoritma, lalu rentang sumber [first, last), lalu data tambahan seperti nilai yang dicari, predikat, atau iterator tujuan. Contoh std::sort(v.begin(), v.end()), std::find(v.begin(), v.end(), nilai), dan std::count_if(v.begin(), v.end(), predikat) memakai kerangka yang sama. Setelah kita hafal satu, sisanya terasa familiar.
Program berikut mendemonstrasikan pola itu termasuk memakai rentang sebagian — sort hanya tiga elemen di tengah vector:
#include <algorithm>
#include <iostream>
#include <vector>
void cetak(const std::vector<int>& v) {
for (std::size_t i = 0; i < v.size(); ++i) {
if (i > 0) std::cout << ' ';
std::cout << v[i];
}
std::cout << '\n';
}
int main() {
std::vector<int> angka = {8, 3, 9, 1, 7, 2, 6};
// Algoritma bekerja pada rentang [first, last) = seluruh vector
std::sort(angka.begin(), angka.end());
std::cout << "Sort penuh : ";
cetak(angka);
// Rentang sebagian [begin+1, begin+4): hanya indeks 1, 2, 3
std::vector<int> sebagian = {8, 3, 9, 1, 7, 2, 6};
std::sort(sebagian.begin() + 1, sebagian.begin() + 4);
std::cout << "Sort 3 tengah: ";
cetak(sebagian);
// Algoritma lain memakai pola begin/end yang sama
int genap = std::count_if(angka.begin(), angka.end(),
[](int x) { return x % 2 == 0; });
std::cout << "Jumlah genap : " << genap << "\n";
// C++20: versi ranges tanpa begin()/end() eksplisit (pratinjau)
std::ranges::sort(angka);
std::cout << "ranges::sort : ";
cetak(angka);
return 0;
}Output yang Dihasilkan:
Sort penuh : 1 2 3 6 7 8 9
Sort 3 tengah: 8 1 3 9 7 2 6
Jumlah genap : 3
ranges::sort : 1 2 3 6 7 8 9Bedah baris penting:
- Baris 17-18 (
std::sort(angka.begin(), angka.end())): rentang penuh[begin, end)mencakup seluruh tujuh elemen, sehingga semuanya terurut menjadi1 2 3 6 7 8 9. - Baris 22-23 (
sebagian.begin() + 1, ... + 4): rentang[begin+1, begin+4)hanya menutupi indeks 1, 2, 3 (nilai3, 9, 1). Hanya segmen itu yang diurut menjadi1 3 9, sementara elemen lain tetap di posisinya — hasilnya8 1 3 9 7 2 6. - Baris 27-28 (
std::count_if(...)): algoritma pencacah memakai rentang penuh dan lambda sebagai kondisi; ada tiga nilai genap di data yang sudah terurut. - Baris 32 (
std::ranges::sort(angka)): versi C++20 menerima container langsung tanpabegin()/end()eksplisit. Hasilnya identik karena secara internal rentang yang sama yang dibentukkan.
Contoh “sort tiga tengah” memperlihatkan keuntungan desain berbasis iterator: memproses sebagian data tidak butuh algoritma baru, cukup iterator yang menunjuk bagian berbeda. Trik serupa dipakai untuk memproses dua container berbeda sekaligus dalam satu panggilan algoritma.
Pratinjau Gaya std::ranges #
Sejak C++20, header <algorithm> juga menyediakan versi ranges: std::ranges::sort, std::ranges::find, std::ranges::count_if, dan seterusnya. Keunggulan praktisnya ada dua: kita mengirim container atau rentang langsung tanpa menuliskan begin()/end(), dan compiler memeriksa lebih awal bila iterator yang kita kirim tidak cocok. Selain itu versi ranges mendukung proyeksi (projection), yaitu alamat member untuk dijadikan kunci operasi.
Meski begitu, gaya iterator klasik tetap wajib dikuasai: mayoritas kode C++ yang beredar memakainya, dan beberapa situasi — misalnya memproses rentang sebagian secara eksplisit — masih paling jelas ditulis dengan begin()/end(). Chapter berikutnya masuk ke algoritma pertama yang wajib dikuasai: std::sort.
Rujukan resmi: daftar algoritma di cppreference dan std::ranges::sort .