C++ map ve unordered_map ile Anahtar-Değer Yapıları
C++ std::map ve std::unordered_map kullanımını öğrenin. Anahtar-değer yapıları, arama performansı ve kullanım senaryolarını örneklerle keşfedin.
C++’ta map ve unordered_map, anahtar-değer (key-value) yapıları sağlayan en temel iki ilişkilendirilmiş (associative) konteynerdir. İkisinin de kullanım amacı aynıdır: Bir anahtar ile ona karşılık gelen değeri hızlı şekilde eşlemek. Ancak veri yapıları, sıralama davranışı, arama süresi ve performans özellikleri birbirinden oldukça farklıdır. Bu makalede her iki yapıyı ayrıntılı şekilde inceleyip örnekleriyle açıklayacağız.
1) map Nedir?
std::map bir kırmızı-siyah ağaç (red-black tree) tabanlı, sıralı bir anahtar-değer konteyneridir.
- Veriler anahtara göre sıralı tutulur.
- Arama, ekleme ve silme işlemleri: O(log n)
- Anahtarlar eşsizdir → aynı anahtar iki kez eklenemez.
- İterasyon her zaman artan anahtar sırasına göredir.
#include <map>
#include <iostream>
using namespace std;
int main() {
map<string, int> scores;
scores["Alice"] = 90;
scores["Bob"] = 80;
scores["Charlie"] = 95;
for (auto& p : scores)
cout << p.first << " -> " << p.second << endl;
}
Sonuç: Charlie, Alice’ten sonra değil → alfabetik sırada listelenir (Alice, Bob, Charlie).
2) unordered_map Nedir?
std::unordered_map, bir hash tablosu tabanlı anahtar-değer yapısıdır. Sıralama garantisi yoktur ancak arama işlemleri ortalamada çok hızlıdır.
- Anahtarlar hash edilir → sıralı değildir.
- Arama, ekleme, silme: ortalama O(1) (en kötü ihtimalle O(n)).
- Sıra bozuk olabilir ve zamanla değişebilir.
- Büyük veri setlerinde map’ten çok daha hızlıdır.
#include <unordered_map>
#include <iostream>
using namespace std;
int main() {
unordered_map<string, int> scores;
scores["Alice"] = 90;
scores["Bob"] = 80;
scores["Charlie"] = 95;
for (auto& p : scores)
cout << p.first << " -> " << p.second << endl;
}
Not: Çıktı sırası tamamen rastlantısal olabilir ve her çalıştırmada farklı olabilir.
3) map vs unordered_map Karşılaştırması
| Özellik | map | unordered_map |
|---|---|---|
| Veri yapısı | Kırmızı-siyah ağaç | Hash tablosu |
| Zaman karmaşıklığı (arama) | O(log n) | O(1) ortalama |
| Sıralı mı? | Evet | Hayır |
| Bellek tüketimi | Daha düşük | Daha yüksek |
| İterasyon | Sıralı | Rastgele |
| Büyük veri setleri | Daha yavaş | Daha hızlı |
Özet: Sıralama önemliyse map; hız önemliyse unordered_map kullanılmalıdır.
4) Temel İşlemler
a) Ekleme
map<int,string> m;
m.insert({1, "One"});
m[2] = "Two"; // hem ekleme hem güncelleme yapar
b) Arama
auto it = m.find(1);
if (it != m.end())
cout << "Bulundu: " << it->second;
c) Silme
m.erase(2); // anahtara göre siler
m.erase(m.begin()); // iterator ile silme
d) Eleman sayısı ve kontrol
cout << m.size();
cout << m.count(1); // 0 veya 1 döner
5) unordered_map için Hash Fonksiyonları
Varsayılan hash fonksiyonları int, string, double gibi temel türler için yeterlidir.
Ancak kendi sınıflarınızda özel hash fonksiyonları yazmanız gerekebilir.
#include <unordered_map>
#include <string>
struct User {
string name;
int id;
};
struct UserHash {
size_t operator()(User const& u) const noexcept {
return hash<string>{}(u.name) ^ hash<int>{}(u.id);
}
};
struct UserEq {
bool operator()(User const& a, User const& b) const noexcept {
return a.id == b.id && a.name == b.name;
}
};
int main() {
unordered_map<User, int, UserHash, UserEq> users;
}
6) Başlık Sıkıştırma (Bucket) Mantığı – unordered_map
unordered_map içindeki veriler bucket denen küçük listelere yerleştirilir. Hash çakışmaları aynı bucket içine düşer.
unordered_map<int,string> um;
cout << um.bucket_count() << endl;
cout << um.load_factor() << endl;
Yük faktörü (load factor) arttıkça performans düşer.
rehash(n) ile bucket sayısı artırılarak hız tekrar yükseltilebilir.
7) Uygulamalı Örnek – Öğrenci Not Sistemi
#include <unordered_map>
#include <iostream>
using namespace std;
int main() {
unordered_map<string, double> grades;
grades["Ali"] = 85.5;
grades["Ayşe"] = 92.0;
grades["Mehmet"] = 78.0;
if (grades.contains("Ayşe"))
cout << "Ayşe'nin notu: " << grades["Ayşe"] << endl;
grades.erase("Mehmet");
for (auto& g : grades)
cout << g.first << ": " << g.second << endl;
}
8) Hangi Durumda Hangisi?
- map → Sıralama gerekiyorsa, veri küçük/orta boyutluysa, ağaç yapıları lazımsa.
- unordered_map → En yüksek arama/ekleme/silme hızını istiyorsanız.
- Küme işlemleri (küçük/büyük eşit aralık aramaları) gerekiyorsa map tercih edilir.
- Büyük veri setlerinde performans açısından unordered_map açıktır.
Genel öneri: Sıralamaya ihtiyacınız yoksa → unordered_map kullanın. Sıralı sekme/iterasyon istiyorsanız → map kullanın.
9) TL;DR
- map: O(log n) – sıralı, ağaç tabanlı, güvenilir iterasyon.
- unordered_map: O(1) ortalama – hash tabanlı, hızlı, sırasız.
- Büyük veri → unordered_map daha hızlı.
- Küçük veri veya sıralama → map daha uygun.
- Özel veri türleri için özel hash fonksiyonları yazılabilir.
- Tüm örnekler Visual Studio 2022 ve GCC 11+ ile uyumludur.