Menu

set C++: elemen unik dan terurut dengan std::set

Cara std::set menyimpan nilai unik yang otomatis terurut di C++: menambah elemen, mengecek keberadaan dengan count dan find, menelusuri secara berurutan, serta perbedaan set, multiset, dan unordered_set.

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

Kantong berisi nilai unik yang terurut

Kamu sudah melihat unordered_map menyimpan pasangan key-value dengan pencarian cepat berbasis hash. std::set adalah saudaranya yang lebih sederhana: ia hanya menyimpan nilai, tanpa data yang terkait, dan secara otomatis menerapkan dua aturan. Setiap elemen unik (duplikat dibuang diam-diam), dan elemen-elemennya selalu dijaga dalam urutan terurut.

Karena itu set adalah pilihan alami untuk pertanyaan seperti "apakah aku sudah pernah melihat ini?" atau "beri aku item-item yang berbeda dalam urutan terurut". Kamu menambahkan elemen tanpa khawatir soal duplikat, dan menelusurinya tanpa perlu mengurutkan dulu.

Perhatikan bahwa kita menambahkan 10 dua kali dan tidak berurutan, tapi output-nya terurut dan 10 hanya muncul sekali. Set sudah mengurus pencatatannya untukmu.

Menambah dan menghapus

insert menambahkan sebuah nilai kalau nilai itu belum ada. Fungsi ini mengembalikan pair yang .second-nya berupa bool, yang memberi tahu apakah penambahan benar-benar terjadi. Ini berguna kalau kamu ingin tahu apakah sebuah nilai itu baru:

Untuk menghapus nilai, panggil erase dengan nilai itu sendiri. Fungsi ini mengembalikan jumlah elemen yang dihapus (0 atau 1 untuk set). Menghapus sesuatu yang tidak ada itu aman, bukan error:

Mengecek keberadaan elemen

Inti dari set adalah pengecekan cepat "apakah ini ada di sini?". Cara yang paling jelas adalah count, yang mengembalikan 1 atau 0:

Sejak C++20 ada pilihan yang lebih mudah dibaca, yaitu contains, yang langsung mengembalikan bool:

if (primes.contains(7)) { /* ... */ }   // C++20

Kesalahan umum adalah memakai operator[] seperti pada map. set tidak punya operator[]: tidak ada nilai yang bisa diambil, yang ada hanya keberadaan yang bisa dicek. Pakai count atau contains, bukan s[7].

Kalau kamu butuh posisi sebenarnya (untuk menghapusnya, atau melihat elemen di sekitarnya), pakai find, yang mengembalikan iterator atau end():

Penelusuran berurutan dan query rentang

Karena set terurut, penelusuran selalu menghasilkan elemen dari yang terkecil sampai terbesar, dan kamu mendapat trik container terurut secara gratis. lower_bound(x) memberi elemen pertama yang tidak lebih kecil dari x, dan upper_bound(x) memberi elemen pertama yang benar-benar lebih besar dari x. Keduanya memungkinkan kamu memindai rentang angka tanpa mengecek setiap elemen:

Ada aturan yang halus tapi penting: elemen set tidak bisa diubah. Iterator memberimu reference const, jadi kamu tidak bisa mengubah elemen di tempatnya, karena itu bisa merusak urutan yang diandalkan container. Untuk "mengubah" sebuah nilai, hapus nilai lama lalu tambahkan nilai yang baru.

Secara default urutannya naik (std::less). Untuk urutan turun, berikan comparator lain sebagai argumen template kedua:

set vs multiset vs unordered_set

std::set adalah salah satu dari tiga kerabat dekat, dan memilih yang tepat itu penting:

set<int>            // unique values, sorted, O(log n)
multiset<int>       // allows duplicates, sorted, O(log n)
unordered_set<int>  // unique values, NO order, average O(1)

Pakai unordered_set kalau kamu hanya butuh pengecekan keberadaan dan tidak peduli urutan: pencarian berbasis hash-nya rata-rata lebih cepat daripada O(log n) berbasis tree milik set. Pilih set kalau kamu butuh elemen dalam urutan terurut, query rentang dengan lower_bound/upper_bound, atau perilaku iterator yang stabil. Pakai multiset hanya kalau duplikat memang bermakna (misalnya histogram dari nilai yang berulang). Di multiset, count(x) bisa mengembalikan lebih dari 1, dan erase(x) menghapus semua salinannya kecuali kamu menghapus lewat satu iterator.

Satu pemakaian klasik set: menghapus duplikat sekaligus mengurutkan vector dalam satu langkah.

Membuat set dari iterator milik vector membuang setiap duplikat dan mengurutkan sisanya, tanpa loop manual dan tanpa repot dengan pengurutan eksplisit plus std::unique.

Berikutnya: pair dan tuple

Kamu sudah melihat .first dan .second muncul pada pair yang dikembalikan insert, dan structured binding yang dipadukan dengan kata kunci auto (auto [it, inserted]) membongkarnya dengan rapi. Tipe ringan untuk "menggabungkan beberapa nilai" seperti itu ada di mana-mana di STL. Berikutnya kita akan membahas pair dan tuple secara langsung: cara membuatnya, membongkarnya, dan mengembalikan banyak nilai dari fungsi tanpa harus mendefinisikan struct.

Pertanyaan yang sering diajukan

Apa itu set di C++?

std::set adalah associative container yang menyimpan nilai unik dalam urutan terurut. Menambahkan nilai yang sudah ada tidak berpengaruh apa-apa, dan penelusuran berjalan dari elemen terkecil sampai terbesar. Pencarian, penambahan, dan penghapusan semuanya O(log n) karena di baliknya ada balanced binary search tree.

Bagaimana cara mengecek apakah sebuah elemen ada di set C++?

Pakai s.count(x) yang mengembalikan 1 kalau x ada dan 0 kalau tidak, atau s.contains(x) di C++20 yang mengembalikan bool. Hindari s.find(x) != s.end() kecuali kamu memang butuh iterator-nya: biayanya sama tapi penulisannya lebih panjang.

Apa perbedaan set dan unordered_set di C++?

std::set menjaga elemennya tetap terurut dan menawarkan operasi O(log n); std::unordered_set menyimpannya tanpa urutan tertentu memakai hash table, dengan rata-rata operasi O(1). Pakai set kalau kamu butuh penelusuran berurutan atau query rentang, dan unordered_set kalau kamu hanya butuh pengecekan keberadaan yang cepat dan tidak peduli urutan.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai