De ce contează?
Gândește-te la agenda de pe telefon. Cauți după nume și primești numărul.
Fiecare nume apare o singură dată, iar lista e afișată ordonată alfabetic, ca să
găsești repede. Asta este un map: cauți după o cheie unică și primești valoarea
ei, totul ținut ordonat după cheie.
Ce este un map și de ce îl folosești
Un map este un dicționar cheie → valoare. Fiecare cheie e unică (nu poți avea două intrări cu aceeași cheie) și cheile sunt ținute ordonate crescător, pentru că map e construit pe un arbore binar echilibrat.
De ce contează asta în concursuri? Pentru că un vector de frecvență obișnuit
(frec[x]++) funcționează doar când x e un întreg mic, pe care îl poți folosi
ca indice. Dar dacă vrei să numeri cuvinte, numere uriașe (până la 10^18)
sau perechi, nu ai cum să declari un vector atât de mare. map rezolvă exact
asta: cheia poate fi orice tip comparabil, iar fiecare operație costă O(log n).
Pe scurt, alegi map când:
- ai chei care nu sunt indici mici (string-uri, numere mari, perechi);
- vrei rezultatul parcurs sortat după cheie, fără efort suplimentar.
Exemplu pas cu pas: frecvența cuvintelor
Vrem să numărăm de câte ori apare fiecare cuvânt în „mar pere mar mar pere”.
Folosim un map<string, int> și incrementăm cu m[cuvant]++:
- citim „mar” →
m["mar"]nu există, devine 0, apoi++→mar: 1 - citim „pere” → devine 0, apoi
++→mar: 1, pere: 1 - citim „mar” → există,
++→mar: 2, pere: 1 - citim „mar” →
++→mar: 3, pere: 1 - citim „pere” →
++→mar: 3, pere: 2
| frec | 3 | 2 |
| cheie | mar | pere |
Truc-ul m[cuvant]++ merge tocmai datorită efectului secundar al lui []: la
prima întâlnire cheia e creată cu 0, apoi incrementată la 1. La numărare e exact
ce vrei — dar reține că acest efect te poate încurca dacă doar citești.
Implementare C++
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> frec;
// numaram cuvintele citite
string cuvant;
while (cin >> cuvant) {
frec[cuvant]++; // creeaza cheia la 0 daca lipseste, apoi ++
}
// verificare PURA: nu cream cheia daca nu exista
if (frec.count("mar")) {
cout << "mar apare de " << frec["mar"] << " ori\n";
}
// find ne da un iterator catre pereche (sau end() daca lipseste)
auto it = frec.find("kiwi");
if (it == frec.end()) {
cout << "kiwi nu exista\n";
}
// parcurgere SORTATA dupa cheie, cu iterator clasic
for (auto it = frec.begin(); it != frec.end(); it++) {
cout << it->first << " -> " << it->second << "\n";
// it->first = cheia, it->second = valoarea
}
// varianta moderna, mai citibila (structured bindings)
for (auto& [k, v] : frec) {
cout << k << " : " << v << "\n";
}
return 0;
}Pentru intrarea „mar pere mar mar pere”, parcurgerea afișează cheile ordonate:
mar -> 3 apoi pere -> 2.
Complexitate
Toate operațiile trec prin arbore, deci sunt logaritmice — nu O(1) ca la vector:
| Operație | Timp | Observație |
|---|---|---|
m[cheie] (acces/creare) | O(log n) | poate insera cheia |
insert | O(log n) | nu suprascrie o cheie existentă |
find / count | O(log n) | citire pură |
| parcurgere completă | O(n) | în ordinea sortată a cheilor |
Parcurgerea unui map îți dă cheile crescător, gratis. Dacă ai nevoie de
rezultatul sortat (ex. afișează frecvențele în ordine alfabetică), map îți
economisește un sort separat — exact diferența față de un dicționar neordonat.
Greșeli frecvente cu map:
m[cheie]la simpla citire creează intrarea:if (m[x] > 0)adaugă pexcu valoarea 0 dacă lipsea. Pentru verificare pură foloseștem.count(x)saum.find(x) != m.end().- Crezi că
insertsuprascrie:m.insert({k, v})NU schimbă valoarea dacă cheia există deja. Pentru suprascriere foloseștem[k] = v. - Ordinea de inserare ≠ ordinea de parcurgere: map parcurge sortat după cheie, nu în ordinea în care ai adăugat. Dacă vrei ordinea de inserare, map nu e structura potrivită.
- Folosești map unde
unordered_mape mai rapid: dacă NU ai nevoie de chei ordonate,unordered_mapdă O(1) mediu în loc de O(log n). map merită doar când ordinea contează.
Vizualizare
Urmărește cum o cheie nouă se așază la locul ei în arbore, păstrând totul ordonat:
Observă unde aterizează o cheie nouă: nu la sfârșit, ci în poziția care menține ordinea. De aceea parcurgerea iese mereu sortată. Folosește ← / → pentru a vedea fiecare inserare pas cu pas.
Recapitulare
- map e dicționar cheie unică → valoare, ținut ordonat după cheie, cu operații O(log n).
m[cheie]creează cheia cu valoare implicită la citire — pentru verificare pură foloseștecountsaufind.- Parcurgi sortat cu
it->first/it->secondsau cufor (auto& [k, v] : m); alegeunordered_mapcând ordinea nu contează.