Mencari sebuah nilai di dalam container adalah kebutuhan harian, dan C++ menyediakan std::find untuk itu: algoritma linier yang memeriksa elemen satu per satu dari first hingga last, membandingkan tiap elemen dengan nilai yang dicari lewat operator==. Sepuluh tahun kuliah ilmu komputer tidak diperlukan untuk menghafalnya — yang penting dipahami adalah nilai kembaliannya, yaitu iterator. std::find mengembalikan iterator ke elemen pertama yang cocok, atau last bila tidak ada yang cocok. Chapter ini membahas std::find, saudaranya find_if untuk kondisi bebas, cara menafsirkan hasil pencarian, dan pola counting untuk menghitung semua kemunculan.

std::find dan Hasil yang Dikembalikan #

Aturan baca hasilnya satu kalimat: bandingkan iterator yang dikembalikan dengan end(). Bila sama, pencarian gagal; bila berbeda, iterator menunjuk elemen yang ditemukan dan selisihnya dengan begin() adalah indeksnya. Program berikut menunjukkan kedua cabang tersebut:

cpp
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> stok = {12, 7, 25, 7, 9, 30};

    // std::find: mencari nilai dengan operator==, linier O(n)
    auto posisi = std::find(stok.begin(), stok.end(), 25);
    if (posisi != stok.end()) {
        std::cout << "25 ditemukan di indeks "
                  << (posisi - stok.begin()) << "\n";
    }

    // end() berarti nilai tidak ditemukan
    auto hilang = std::find(stok.begin(), stok.end(), 99);
    std::cout << "Cari 99: "
              << (hilang == stok.end() ? "tidak ditemukan" : "ditemukan")
              << "\n";

    // find_if: kondisi bebas lewat lambda
    auto pertamaGenap = std::find_if(stok.begin(), stok.end(),
                                     [](int x) { return x % 2 == 0; });
    std::cout << "Genap pertama: " << *pertamaGenap << "\n";

    // Pola counting: ulangi find dari posisi setelah temuan terakhir
    int jumlahTujuh = 0;
    for (auto it = std::find(stok.begin(), stok.end(), 7);
         it != stok.end();
         it = std::find(it + 1, stok.end(), 7)) {
        ++jumlahTujuh;
    }
    std::cout << "Angka 7 muncul: " << jumlahTujuh << " kali\n";
    return 0;
}

Output yang Dihasilkan:

text
25 ditemukan di indeks 2
Cari 99: tidak ditemukan
Genap pertama: 12
Angka 7 muncul: 2 kali

Bedah baris demi baris:

  1. Baris 8-11 (std::find(stok.begin(), stok.end(), 25)): pencarian nilai 25 berhasil; posisi menunjuk elemen tersebut dan posisi - stok.begin() menghasilkan indeks 2. Pengurangan iterator sah di sini karena vector memberi random access.
  2. Baris 14-16: nilai 99 tidak ada, sehingga hasil std::find sama dengan end(). Kode kita menafsirkannya sebagai "tidak ditemukan" — inilah konvensi yang dipakai semua algoritma pencarian.
  3. Baris 19-21 (std::find_if): alih-alih nilai tetap, kita mengirim lambda x % 2 == 0. find_if mengembalikan elemen pertama yang membuat lambda menghasilkan true; di data ini 12.
  4. Baris 24-29: pola counting. Loop dimulai dari temuan pertama; setiap iterasi mencari lagi mulai it + 1, sehingga setiap kemunculan 7 dihitung satu kali hingga end() tercapai. Hasilnya dua kali.

Pola counting di baris 24-29 sesungguhnya bisa digantikan std::count (Chapter berikutnya pada bagian pencacahan), tetapi bentuk ini bermanfaat saat kita butuh posisi setiap kemunculan, bukan sekadar jumlahnya.

find_if untuk Kondisi Bebas #

std::find hanya bisa membandingkan kesamaan nilai. Dunia nyata sering bertanya lain: “cari mahasiswa dengan nilai di bawah 60”, “cari produk yang stoknya nol”, “cari string yang kosong”. Untuk pertanyaan-pertanyaan seperti itu, find_if menerima predikat — fungsi satu argumen yang mengembalikan bool. Kombinasi lambda dan find_if menjadi alat pencarian paling serbaguna karena kondisinya ditulis langsung di tempat pemanggilan.

Ada juga varian find_if_not yang mencari elemen pertama yang tidak memenuhi predikat, serta std::search untuk mencari sub-urutan di dalam urutan yang lebih panjang. Keluarga ini semuanya linier dan hanya menuntut input iterator, sehingga aman dipakai di container mana pun, termasuk std::list dan std::set.

Satu kebiasaan yang patut dijaga: selalu periksa hasil terhadap end() sebelum mendereference. Menulis *std::find(...) langsung tanpa pemeriksaan adalah bug menunggu data berubah, karena bila nilai tidak ditemukan kita sedang mendereference end() — perilaku undefined.

Berikutnya kita naikkan kecepatan pencarian dengan menuntut syarat pada data: binary search, lower_bound, upper_bound, dan equal_range.

Rujukan resmi: std::find, find_if, find_if_not .