Menu

C++ set: std::set ile benzersiz, sıralı elemanlar

std::set'in C++'ta benzersiz ve otomatik olarak sıralanmış değerleri nasıl sakladığı: ekleme, count ve find ile üyelik kontrolü, sıralı dolaşma ve set, multiset ile unordered_set arasındaki farklar.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Benzersiz ve Sıralı Değerlerden Oluşan Bir Torba

unordered_map'in anahtar-değer çiftlerini hızlı karma tabanlı aramayla nasıl sakladığını görmüştün. Bir std::set ise daha sade bir kuzendir: yalnızca değerleri saklar — ilişkili veri yoktur — ve iki kuralı otomatik olarak uygular. Her eleman benzersizdir (yinelenenler sessizce atılır) ve elemanlar her zaman sıralı düzende tutulur.

Bu da set'i "bunu daha önce gördüm mü?" ya da "bana farklı öğeleri sıralı ver" gibi sorular için doğal bir tercih yapar. Yinelenenleri dert etmeden eklersin ve önce sıralamadan dolaşırsın.

10'u iki kez ve sırasız eklediğimize dikkat et; yine de çıktı sıralı ve 10 bir kez görünüyor. Defter tutmayı set senin yerine yaptı.

Ekleme ve Silme

insert, bir değer henüz yoksa onu ekler. Ekleme işleminin gerçekten gerçekleşip gerçekleşmediğini söyleyen, .second'ı bir bool olan bir pair döndürür — bir değerin yeni olup olmadığını bilmek istediğinde işe yarar:

Bir değeri silmek için erase'i değerin kendisiyle çağır; silinen eleman sayısını döndürür (bir set için 0 ya da 1). Olmayan bir şeyi silmek zararsızdır, hata değildir:

Üyeliği Kontrol Etme

Bir set'in tüm amacı hızlı "bu burada mı?" testleridir. En açık yol, 1 ya da 0 döndüren count'tur:

C++20'den beri daha da okunabilir bir seçenek var: doğrudan bool döndüren contains:

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

Yaygın bir hata, bir map'te yapacağın gibi operator[]'e başvurmaktır. Bir set'in operator[]'i yoktur: getirilecek bir değer yoktur, yalnızca test edilecek bir varlık vardır. s[7] değil, count ya da contains kullan.

Gerçek konuma ihtiyacın varsa (silmek ya da komşulara bakmak için), bir yineleyici veya end() döndüren find'ı kullan:

Sıralı Dolaşma ve Aralık Sorguları

Bir set sıralı olduğundan, dolaşma her zaman elemanları küçükten büyüğe verir ve sıralı konteyner numaralarını bedavaya elde edersin. lower_bound(x), x'ten küçük olmayan ilk elemanı; upper_bound(x) ise x'ten kesinlikle büyük olan ilk elemanı verir — birlikte, her elemanı kontrol etmeden sayısal bir aralığı taramana izin verirler:

İnce ama önemli bir kural: set elemanları değiştirilemez. Yineleyici sana bir const referans verir, bu yüzden bir elemanı yerinde değiştiremezsin — bunu yapmak, konteynerin dayandığı sıralamayı bozabilir. Bir değeri "değiştirmek" için eskisini sil ve yenisini ekle.

Varsayılan olarak sıralama artandır (std::less). Azalan sıra için ikinci şablon argümanı olarak farklı bir karşılaştırıcı ver:

set vs multiset vs unordered_set

std::set, üç yakın akrabadan biridir ve doğru olanı seçmek önemlidir:

set<int>            // benzersiz değerler, sıralı, O(log n)
multiset<int>       // yinelenenlere izin verir, sıralı, O(log n)
unordered_set<int>  // benzersiz değerler, SIRASIZ, ortalama O(1)

Yalnızca üyelik testlerine ihtiyacın olduğunda ve sıra önemli değilse unordered_set'e başvur — karma tabanlı aramaları, ortalamada set'in ağaç tabanlı O(log n)'inden daha hızlıdır. Elemanları sıralı düzende, lower_bound/upper_bound ile aralık sorguları ya da kararlı yineleyici davranışı istediğinde set'i seç. multiset'i yalnızca yinelenenler anlamlıysa kullan (örneğin, tekrarlanan değerlerin bir histogramı): bir multiset'te count(x) 1'den fazlasını döndürebilir ve tek bir yineleyiciyle silmediğin sürece erase(x) tüm kopyaları kaldırır.

set'in klasik bir kullanımı: bir vector'ü tek hamlede hem yinelenenlerden arındır hem sırala.

Set'i vector'ün yineleyicilerinden oluşturmak her yineleneni atar ve geri kalanı sıralar — elle döngü yok, std::sort artı std::unique dansı yok.

Sıradaki: pair ve tuple

insert'in döndürdüğü pair üzerinde .first ve .second'ın belirdiğini ve yapısal bağların (auto [it, inserted]) onu temizce açtığını gördün. "Birkaç değeri bir araya getiren" bu hafif tipler, STL'in her yerinde. Sırada pair ve tuple'a doğrudan bakacağız: onları nasıl oluşturacağını, açacağını ve koca bir struct tanımlamadan bir fonksiyondan birden çok değeri nasıl döndüreceğini.

Sıkça Sorulan Sorular

C++'ta set nedir?

Bir std::set, benzersiz değerleri sıralı düzende saklayan ilişkisel bir konteynerdir. Zaten var olan bir değeri eklemek hiçbir şey yapmaz ve dolaşma elemanları küçükten büyüğe gezer. Aramalar, eklemeler ve silmeler hep O(log n)'dir çünkü altta dengeli bir ikili arama ağacı vardır.

C++ set'inde bir elemanın var olup olmadığını nasıl kontrol ederim?

x varsa 1, yoksa 0 döndüren s.count(x)'i, ya da C++20'de bool döndüren s.contains(x)'i kullan. Gerçekten yineleyiciye ihtiyacın yoksa s.find(x) != s.end() kullanmaktan kaçın; maliyeti aynı ama daha uzundur.

C++'ta set ile unordered_set arasındaki fark nedir?

std::set elemanları sıralı tutar ve O(log n) işlemler sunar; std::unordered_set ise bir karma tablo kullanarak onları belirli bir sırada tutmaz ve ortalama O(1) işlemler sağlar. Sıralı dolaşmaya veya aralık sorgularına ihtiyacın olduğunda set'i, yalnızca hızlı üyelik testlerine ihtiyacın varken sıra önemli değilse unordered_set'i kullan.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA