Menu

C++ std::map: Anahtarlar, Değerler, Arama ve Ekleme

C++ std::map açıklandı: logaritmik aramaya sahip, anahtara göre sıralı bir anahtar-değer konteyneri. Ekle, bul, dolaş ve anahtarları sessizce ekleyen klasik operator[] tuzağından kaçın.

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

Anahtara Göre Arama Yapma

vector, konuma göre indeksleme yaptığında harikadır: 0. eleman, 1. eleman vesaire. Ama çoğu zaman bir konumun yoktur; bir adın vardır ve ona bağlı şeyi istersin: bir kullanıcı ve puanı, bir kelime ve kaç kez geçtiği, bir ülke kodu ve başkenti. Eşleşme bulmak için bir vector'ü taramak O(n)'dir ve hızla yavaşlar.

std::map bunu çözer. Anahtar-değer çiftleri saklar, onları anahtara göre sıralı tutar ve bir değeri anahtarına göre O(log n) zamanda bulmana izin verir. Kullanmak için <map> ekle:

map<string, int> "string anahtarlardan int değerlere bir map" diye okunur. Anahtarlar benzersizdir: aynı anahtara iki kez atarsan ikinci değer kazanır. İçinde bir map dengeli bir ikili arama ağacıdır; her şeyin sıralı kalmasının ve aramaların sabit değil de logaritmik olmasının nedeni budur.

Eleman Ekleme

Giriş eklemenin birkaç yolu vardır ve aralarındaki fark önemlidir. En yaygın olanı, anahtar yoksa onu oluşturan ve atayabileceğin bir referans döndüren operator[]'tir:

Mevcut bir anahtarın üzerine yazmayı reddeden bir ekleme istiyorsan insert veya emplace kullan. Her ikisi de .second üyesi, eklemenin gerçekten gerçekleşip gerçekleşmediğini söyleyen bir bool olan bir pair döndürür:

"Son yazma kazanır" istediğinde [] kullan; mevcut bir anahtarın el değmeden kalması gerektiğinde insert/emplace kullan.

operator[] Tuzağı: Okurken Ekler

Bu, en yaygın map hatasıdır. operator[] saf bir okuma değildir: anahtar yoksa, onu varsayılan olarak oluşturulmuş bir değerle (int için 0, string için "" vb.) sessizce ekler ve ona bir referans döndürür. Yani bir anahtarı yalnızca [] ile kontrol etmek bile map'i değiştirir:

map<string, int> m;
if (m["maybe"] == 0) {   // HATA: bu az önce "maybe" -> 0 oluşturdu
    // ...
}
cout << m.size();        // 0 değil 1 - yanlışlıkla bir anahtar ekledin

Bu, const map ile de seni ısırır; orada operator[] ekleme yapması gerekebileceği için derlenmez bile. Eklemeden okumak için find, count/contains veya at kullan:

Pratik kural: niyetin okumaksa asla []'e başvurma. Anahtarın var olması gerektiğinde at, var olmayabileceği durumda find/contains kullan.

Sıralı Dolaşma

Bir map ağaca dayalı olduğundan, onu dolaşmak anahtarları her zaman ve bedavadan artan sıralı düzende ziyaret eder. Her eleman bir pair<const Key, Value>'dir; bu yüzden anahtar ile değeri temiz bir şekilde açmak için bir yapısal bağlama kullan:

Bağlamadaki anahtarın const olduğuna dikkat et: bir değeri döngü içinde auto& ile değiştirebilirsin ama bir anahtarı yerinde asla değiştiremezsin (bu sıralamayı bozar). Çıktı, hiçbir sıralama adımı olmadan alfabetik sırada (blue, sea, sky) gelir; insanların sıralı gezinme önemli olduğunda bir hash tablosu yerine map'i seçmesinin nedeni tam olarak budur.

O wordCount[w]++ deyimi, erişimde-ekleme davranışının en tipik kullanımıdır: burada eksik bir anahtarın 0'dan başlamasını istersin, dolayısıyla [] doğru araçtır.

Eleman Silme ve Boyut

Anahtara göre erase ile sil; bu, kaç elemanın kaldırıldığını döndürür (bir map için 0 ya da 1). find'dan gelen bir yineleyiciyle de silebilirsin. Konteynerin durumunu size() ve empty() ile kontrol et:

Bir döngü içinde silerken bir tuzak: m.erase(it), it'yi geçersiz kılar; bu yüzden sonrasında ++it yapamazsın. C++11'den beri güvenli desen, bir sonraki elemana bir yineleyici döndüren it = m.erase(it)'dir. Tüm map boyunca tek seferlik koşullu kaldırma için std::erase_if(m, predicate) (C++20) daha temizdir.

Sıradaki: unordered_map

std::map sana sıralı anahtarlar ve öngörülebilir O(log n) işlemler verir ama bu sıralamanın bedelini her aramada ödersin. Anahtar sırasını umursamayıp yalnızca mümkün olan en hızlı aramaları istediğinde, unordered_map sıralı ağacı bir hash tablosuyla değiştirir: ortalama O(1) erişim. Sıradaki bölümde nasıl çalıştığını, ortalama sabit zamanının map'in logaritmasını ne zaman geçtiğini ve beraberinde gelen hashleme tuzaklarını (özel anahtar türleri, en kötü durumdaki çakışmalar) göreceğiz.

Sıkça Sorulan Sorular

C++'ta std::map nedir?

std::map, anahtar-değer çiftlerini anahtara göre sıralı tutan ilişkisel bir konteynerdir. Arama, ekleme ve silme işlemlerinin hepsi O(log n)'dir çünkü altında dengeli bir ikili arama ağacı bulunur. Her anahtar benzersizdir; aynı anahtarı tekrar eklemek mevcut değere hiçbir şey yapmaz.

C++ map'te operator[] ile at() arasındaki fark nedir?

map[key], değere bir referans döndürür ve anahtar yoksa onu varsayılan olarak oluşturulmuş bir değerle sessizce ekler. map.at(key) de bir referans döndürür ama anahtar yoksa eklemek yerine std::out_of_range fırlatır. Yalnızca okumak istediğinde at() (veya find()) kullan.

C++ map'te bir anahtarın var olup olmadığını nasıl kontrol ederim?

m.contains(key) (C++20), 0 ya da 1 döndüren m.count(key) veya m.find(key) != m.end() kullan. m[key] ile test etmekten kaçın: bu, anahtar yoksa onu ekler, ki bu nadiren istediğin şeydir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA