C++ STL
map / multimap / unordered_map
Complete lesson for map / multimap / unordered_map using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — map / multimap / unordered_map
Section: C++ STL. C++ map family — map, multimap, unordered_map with real-life examples and comparisons.
What is a map family?
- **Map-like** containers store **key → value** associations.
map— **unique** keys, always **sorted** by key (balanced tree).multimap— **duplicate keys allowed**, still **sorted** by key.unordered_map— **unique** keys via **hashing** (no sorted order).- Headers:
#includeand#include. - **Real-life:** phone book (name → number) with
map; one student → many marks withmultimap; shopping-cart item counts withunordered_map.
| Idea | Meaning |
|---|---|
| Key → value | Each entry links a key to a mapped value |
| Unique vs multi | map/unordered_map one value per key; multimap many |
| Order | Tree maps sorted by key; hash map unordered |
| Lookup | Tree O(log n); hash avg O(1) |
[] | On map/unordered_map: may **insert** default if missing |
Why use map / multimap / unordered_map?
- Natural model for dictionaries, indexes, counters, and caches.
- Tree maps give sorted-by-key reports “for free”.
- Hash maps shine for fast lookup when order does not matter.
| Benefit | What you gain |
|---|---|
| Association | Store data under a meaningful key |
| Sorted keys | map/multimap iterate ascending by key |
| Fast dictionary | unordered_map average O(1) access |
| Multi-index | multimap one key → many records |
| Counters | m[key]++ pattern for frequencies |
Which map container?
- Pick by **duplicate keys**, **order**, and **speed**.
| Container | Duplicate keys? | Order | Typical cost | Header | Real-life pick |
|---|---|---|---|---|---|
map | No | Sorted by key | O(log n) | | Phone book, sorted roster |
multimap | Yes | Sorted by key | O(log n) | | Student → many scores |
unordered_map | No | Hash order | Avg O(1) | | Word counts, caches |
Differences between map, multimap, unordered_map
- Same “dictionary” idea — different uniqueness and ordering contracts.
| Feature | map | multimap | unordered_map |
|---|---|---|---|
| Duplicate keys | No | Yes | No |
| Order | Sorted by key | Sorted by key | Unspecified |
| Structure | Tree | Tree | Hash table |
| insert/find | O(log n) | O(log n) | Avg O(1) |
operator[] | Yes (may insert) | No | Yes (may insert) |
at(k) | Yes (throws) | No | Yes (throws) |
| Many values/key | Use nested container | Native | Use nested container |
| Real-life | Name → phone | Name → marks list | SKU → stock count |
map vs set (quick)
setstores **keys only**;mapstores **key → value**.- **Real-life:** guest list of IDs →
set; guest ID → seat number →map.
| Need | Use |
|---|---|
| Only membership / unique keys | set / unordered_set |
| Key with associated data | map / unordered_map |
| Sorted unique keys, no payload | set |
| Sorted unique keys + payload | map |
map — unique sorted keys
- Keys are **unique** and **sorted**; each key maps to one value.
operator[]**inserts** a default value if the key is missing.- Prefer
find/atwhen you must not insert accidentally (atthrows if missing). - **Real-life:** phone book (name → number); employee ID → salary in ID order; country code → capital.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> ages;
ages["Ann"] = 20;
ages.insert({"Bob", 22});
cout << ages["Ann"] << "\n";
if (ages.find("Zoe") == ages.end()) cout << "missing\n";
return 0;
} multimap — duplicate keys allowed
- Same key can appear **many times** with different values.
- **No**
operator[]— useinsertandequal_rangeto read all values for a key. - Useful for indexes: one category → many items.
- **Real-life:** student name → multiple course scores; department → many employees; tag → many blog posts.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
multimap<string, int> scores;
scores.insert({"Ali", 90});
scores.insert({"Ali", 85});
auto [lo, hi] = scores.equal_range("Ali");
for (auto it = lo; it != hi; ++it)
cout << it->second << " ";
cout << "\n";
return 0;
} unordered_map — unique hashed keys
- Unique keys; **not sorted** — ideal for dictionaries and counters.
- Average **O(1)** lookup;
[]inserts a default if missing. reserve(n)can reduce rehashing when size is known.- **Real-life:** word frequency in a document; product SKU → price lookup; session token → user data cache.
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
unordered_map<string, int> cnt;
cnt["apple"]++;
cnt["apple"]++;
cnt["banana"]++;
cout << cnt["apple"] << "\n"; // 2
return 0;
} Common patterns
- Iterate:
for (auto& [k, v] : m)(C++17 structured bindings). - Check before insert:
if (m.find(k) == m.end()) …. - Counters:
unordered_map+m[key]++is a classic interview pattern.
| Need | Prefer |
|---|---|
| Sorted unique key→value | map |
| One key, many values (sorted) | multimap |
| Fast dictionary / counter | unordered_map |
| Must not auto-insert on miss | find / at (not []) |
Real-life examples by container
- Map everyday problems to the right map type.
| Real-life situation | Best fit | Why |
|---|---|---|
| Phone book: name → number, A–Z printout | map | Unique keys + sorted names |
| Employee ID → salary report by ID | map | Sorted unique IDs |
| Country → capital dictionary | map | Ordered lookup / display |
| Student → several exam marks | multimap | Same name, many values |
| Genre → many movie titles | multimap | One key, many records |
| Hotel room type → many room numbers | multimap | Category index |
| Word frequency in a chat log | unordered_map | Fast counter, order unused |
| Shopping cart: SKU → quantity | unordered_map | Fast update by key |
| Browser cache: URL → page bytes | unordered_map | O(1) get/put |
| Config flag → on/off value | unordered_map or map | Hash if speed; map if sorted dump |
Map family applications
- Maps appear whenever you look up or update data by a key.
| Application | Container | How it helps |
|---|---|---|
| Dictionary / phone book | map | Key → value, sorted report |
| Frequency counting | unordered_map | m[k]++ in average O(1) |
| Caching / memoization | unordered_map | Store computed results by input |
| Symbol table (compilers) | map / unordered_map | Name → type/address |
| Inverted index (tag → posts) | multimap | One tag, many post IDs |
| Graph adjacency (node → weight) | map or nested | Neighbor keyed maps |
| Histogram / bin counts | unordered_map | Bin label → count |
| Localization: key → translated string | unordered_map | Fast message lookup |
| Inventory: product → stock | unordered_map | Update quantity by SKU |
| Leaderboard by unique player ID | map | ID → score, sorted IDs |
Application — phone book (map)
- **Real-life:** store contacts; print alphabetically by name.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, string> phone;
phone["Ann"] = "555-0101";
phone["Bob"] = "555-0199";
phone["Ann"] = "555-0111"; // updates unique key
for (auto& [name, num] : phone)
cout << name << " -> " << num << "\n";
return 0;
} Application — student marks index (multimap)
- **Real-life:** one student takes several tests; list all marks for that name.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
multimap<string, int> marks;
marks.insert({"Ali", 90});
marks.insert({"Ali", 85});
marks.insert({"Bea", 88});
auto [lo, hi] = marks.equal_range("Ali");
cout << "Ali: ";
for (auto it = lo; it != hi; ++it) cout << it->second << " ";
cout << "\n";
return 0;
} Application — word counter (unordered_map)
- **Real-life:** count how often each word appears in a message.
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
unordered_map<string, int> freq;
for (string w : {"hi", "hi", "bye", "hi"}) freq[w]++;
for (auto& [w, n] : freq) cout << w << " " << n << "\n";
return 0;
} When to use which
- Need ordered keys or range queries by key order → **
map**. - Need many values per key in order → **
multimap**. - Need speed and uniqueness, order irrelevant → **
unordered_map**. - **Real-life rule of thumb:** alphabetical directory →
map; one person many records →multimap; cart/cache/counter →unordered_map.
Key points to remember
map= unique + sorted;multimap= duplicates + sorted;unordered_map= unique + hash.m[k]may **insert** a default — usefind/atwhen that is unwanted.multimaphas **no**operator[].- set = keys only; map = key → value.
- Real-life: phone book → map; marks index → multimap; word counts → unordered_map.
Advanced — map / multimap / unordered_map
[] vs insert vs at
m[k]creates a default value ifkis new (map / unordered_map).insertdoes not overwrite an existing unique key.at(k)throwsout_of_rangeif missing — never inserts.multimaphas no[]/atfor a single value.- **Real-life pitfall:** checking
if (phone["Zoe"])silently adds Zoe with an empty/default number.
Application — shopping cart (unordered_map)
- **Real-life:** SKU → quantity; increment when user adds an item.
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
unordered_map<string, int> cart;
auto add = [&](const string& sku, int n = 1) { cart[sku] += n; };
add("TEA");
add("TEA");
add("MUG", 2);
for (auto& [sku, qty] : cart)
cout << sku << " x" << qty << "\n";
return 0;
} Application — config / cache idea
- Store
setting → valueorkey → cached resultinunordered_map. - **Real-life:** feature flags; memoize expensive API results by request id.
Iteration and order
map/multimapiterate keys in sorted order.unordered_mapiteration order is unspecified and can change after rehash.- **Real-life:** print directory A–Z with
map; do not rely on hash order for a report.
Complexity & hashing
- Tree maps: O(log n) per lookup.
- Hash maps: average O(1); custom key types need hash + equality.
reserveonunordered_mapwhen you know approximate size.
Design tips
- Need sorted keys →
map/multimap; only fast lookup →unordered_map. - Many values per key →
multimapormap.> - Never use
[]just to test presence. - Prefer structured bindings:
for (auto& [k, v] : m). - Document real-life meaning of key and value (ID, price, count).
Tricky Interview Points
Q1) map vs unordered_map?
Answer map is ordered (tree, O(log n)); unordered_map is hashed (average O(1)) with no sorted order.
Q2) map vs multimap?
Answer map requires unique keys; multimap allows duplicate keys, each with a value.
Q3) What does map operator[] do if the key is missing?
Answer It default-constructs a value for that key and inserts it, then returns a reference.
Q4) Why is there no operator[] on multimap?
Answer A key can map to many values, so a single reference result would be ambiguous.
Q5) Best container for a frequency counter?
Answer unordered_map is usual for word/int counts when order does not matter.
Q6) Give a real-life example for map.
Answer Phone book name→number; employee ID→salary printed in ID order.
Q7) Give a real-life example for multimap.
Answer Student name→several exam marks; genre→many movie titles.
Q8) Give a real-life example for unordered_map.
Answer Word frequency; shopping cart SKU→qty; URL→cached page.
Q9) map vs set?
Answer set stores keys only; map stores key→value pairs.
Q10) How do you read all values for one key in multimap?
Answer equal_range(key) and iterate [first, second).
Q11) insert vs operator[] on map?
Answer insert does not overwrite an existing key; [] assigns and may insert a default first.
Q12) When prefer map over unordered_map?
Answer When you need sorted keys, ordered traversal, or ordered range queries.
Simple Programs
map — ages dictionary
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> ages{{"Ann", 20}, {"Bob", 22}};
for (auto& [name, age] : ages)
cout << name << " " << age << "\n";
return 0;
} multimap — multiple scores
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
multimap<string, int> m;
m.insert({"Ali", 90});
m.insert({"Ali", 70});
m.insert({"Bea", 88});
for (auto& [k, v] : m) cout << k << ":" << v << "\n";
return 0;
} unordered_map — word count
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main() {
unordered_map<string, int> freq;
for (string w : {"a", "b", "a", "c", "b", "a"}) freq[w]++;
for (auto& [w, n] : freq) cout << w << " " << n << "\n";
return 0;
} Real-life — phone book (map)
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, string> book{{"Ann", "111"}, {"Bob", "222"}};
cout << book.at("Ann") << "\n";
if (book.find("Zoe") == book.end()) cout << "no Zoe\n";
return 0;
} Real-life — department staff (multimap)
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
multimap<string, string> dept;
dept.insert({"HR", "Ada"});
dept.insert({"HR", "Ben"});
dept.insert({"IT", "Cara"});
auto [lo, hi] = dept.equal_range("HR");
for (auto it = lo; it != hi; ++it) cout << it->second << " ";
cout << "\n";
return 0;
} Real-life — cart quantities (unordered_map)
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
unordered_map<string, int> cart;
cart["milk"] += 1;
cart["eggs"] += 12;
cart["milk"] += 1;
cout << "milk " << cart["milk"] << "\n";
return 0;
} Problem Solving Tricks
- map = unique + sorted; multimap = duplicates + sorted; unordered_map = unique + hash.
- m[k] may insert — use find/at when that is unwanted.
- multimap has no operator[].
- unordered_map is the usual frequency-counter tool.
- Iterate map/multimap for sorted keys.
- Reserve unordered_map when you know approximate size.
- Real-life: phone book → map; marks/tags index → multimap; cart/cache → unordered_map.
- set = keys only; map = key → value.
- equal_range is the multimap “all values for this key” tool.
- Structured bindings: for (auto& [k, v] : m).
- Prefer at() when missing keys should be errors.
- Document what key and value mean in the real problem.
Practice Programs List
- Build a map of names to ages; print in sorted name order.
- Use multimap to store two scores for the same student; print equal_range.
- Count word frequencies with unordered_map.
- Show that ages["Zoe"] inserts 0 into a map of int values.
- Write a choose-table for map vs multimap vs unordered_map.
- Model a phone book; update one number; print A–Z.
- Model department → employees with multimap; list one department.
- Model a shopping cart SKU→qty; add the same SKU twice.
- List 8 real-life examples and pick the best map container for each.
- Explain a bug caused by using [] only to “check” a key.
- Rewrite a frequency counter using find + insert instead of [].
- Compare map vs set for “ID only” vs “ID → seat number”.