De ce contează?
Imaginează-ți catalogul unei biblioteci, organizat după autor. Cauți „Eminescu”
și nu primești o singură carte, ci toate cărțile lui, una sub alta. Un autor are
mai multe opere, iar catalogul le ține pe toate sub același nume. Exact așa
lucrează un multimap: o cheie, mai multe valori, toate păstrate.
Ce este un multimap și de ce diferă de map
Un map leagă fiecare cheie de o singură valoare. Dacă inserezi din nou aceeași cheie, vechea valoare se pierde sau este ignorată. Bun pentru „CNP → nume”, unde un CNP are un singur nume.
Dar ce faci când o cheie are mai multe valori? „autor → cărți”, „oraș →
locuitori”, „cuvânt → paginile unde apare”. Aici intră multimap: păstrează
toate perechile, chiar dacă au aceeași cheie. Stă tot în <map>, este tot
ordonat crescător după cheie și are tot operații în O(log n).
Diferența cheie: pentru că o cheie are mai multe valori, multimap NU are
operator[]. Nu ai cum să scrii m[cheie] — care dintre valori ar trebui să
returneze? Adaugi mereu cu insert({cheie, val}).
Exemplu pas cu pas
Construim un index invers: cuvânt → paginile pe care apare. Inserăm pe rând:
insert({"alfa", 1})→alfaapare la pagina 1insert({"beta", 2})→betala pagina 2insert({"alfa", 5})→alfaare acum două valori: 1 și 5insert({"alfa", 9})→alfaare trei: 1, 5, 9
Structura ține toate perechile, grupate și ordonate după cheie:
alfa -> 1
alfa -> 5
alfa -> 9
beta -> 2Acum count("alfa") întoarce 3, iar count("gama") întoarce 0. Ca să vezi
toate paginile lui alfa, ceri intervalul lor cu equal_range("alfa").
Implementare C++
equal_range(cheie) întoarce o pereche {first, second}: first arată spre
prima apariție a cheii, second arată imediat după ultima. Parcurgi de la
first până la second (interval semideschis, ca la begin/end).
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
multimap<string, int> index;
// insert: o cheie poate primi mai multe valori
index.insert({"alfa", 1});
index.insert({"beta", 2});
index.insert({"alfa", 5});
index.insert({"alfa", 9});
cout << index.count("alfa") << "\n"; // 3 valori pentru alfa
cout << index.count("gama") << "\n"; // 0 (cheie inexistenta)
// equal_range: parcurgem TOATE valorile cheii "alfa"
auto interval = index.equal_range("alfa");
cout << "alfa apare la paginile:";
for (auto it = interval.first; it != interval.second; ++it) {
cout << " " << it->second; // it->first e cheia, it->second valoarea
}
cout << "\n";
return 0;
}Rezultat la rulare:
3
0
alfa apare la paginile: 1 5 9Observă: nicăieri nu apare index[...], pentru că multimap nu permite. Tot ce
ține de o cheie trece prin insert, equal_range și count.
Complexitate
| Operație | Timp |
|---|---|
insert({cheie, val}) | O(log n) |
count(cheie) | O(log n + k)* |
equal_range(cheie) | O(log n) |
| parcurgerea unei chei cu k valori | O(k) |
*k = numărul de valori ale cheii. Localizarea cheii e O(log n); parcurgerea
celor k valori adaugă O(k).
Iteratorii din equal_range formează un interval semideschis [first, second):
first este inclus, second este exclus (la fel ca begin() și end()).
Bucla merge it != second, nu it <= second.
| multimap | (alfa | 1) | (alfa | 5) | (alfa | 9) | (beta | 2) |
first | second |
Greșeli frecvente cu multimap:
- Cauți
m[cheie]: nu există operator[] la multimap. Compilatorul dă eroare. Foloseșteinsert({cheie, val})la scriere șiequal_rangela citire. - Crezi că
counte 0 sau 1: pe multimap poate fi orice număr — e câte valori are cheia. - Tratezi
secondca pe ultima valoare:equal_rangedă[first, second), deciseconde după ultima valoare, nu pe ea. Nu o dereferenția. - Confuzia cu map: dacă reinserezi o cheie pe
multimap, vechea valoare NU se pierde — se adaugă una nouă. Vrei o singură valoare pe cheie? Atunci ai nevoie demap, nu demultimap.
Recapitulare
multimapleagă o cheie de mai multe valori; e ordonat, cu operațiiO(log n), din<map>.- NU are operator[]: adaugi cu
insert({cheie, val}), numeri cucount, citești o cheie cuequal_range. equal_range(cheie)dă intervalul[first, second)— parcurgiit != secondși citești valoarea cuit->second.