Skip to main content

C++ STL

set / multiset / unordered_set

Complete lesson for set / multiset / unordered_set using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.

L1

Basics — set / multiset / unordered_set

Section: C++ STL. C++ set family — set, multiset, unordered_set with real-life examples and comparisons.

What is a set family?

  • **Set-like** containers store **keys only** (no mapped value like map).
  • set — **unique** keys, always **sorted** (balanced tree).
  • multiset — **duplicates allowed**, still **sorted**.
  • unordered_set — **unique** keys via **hashing** (no sorted order).
  • Headers: #include and #include .
  • **Real-life:** guest list without repeats (set); score sheet with tied marks (multiset); “have I seen this ID?” badge scanner (unordered_set).
IdeaMeaning
Key-onlyStores elements, not key→value pairs
Unique vs multiset/unordered_set reject duplicates; multiset keeps them
OrderTree sets sorted; hash set unordered
LookupTree O(log n); hash avg O(1)
IterateRange-for walks all keys

Why use set / multiset / unordered_set?

  • Fast membership tests and automatic uniqueness (or sorted multis).
  • Tree sets give ordered traversal “for free”.
  • Hash sets shine when order does not matter and speed does.
BenefitWhat you gain
UniquenessNo manual “already present?” for set / unordered_set
Sorted walkset/multiset iterate ascending
Fast lookupunordered_set average O(1) membership
Duplicate countsmultiset::count for frequency
Clear intentBetter than a hand-rolled sorted vector for keys

Which set container?

  • Pick by **duplicates** and whether you need **sorted order**.
ContainerDuplicates?OrderTypical costHeaderReal-life pick
setNo (unique)SortedO(log n)Unique roll numbers, sorted tags
multisetYesSortedO(log n)Exam scores with ties
unordered_setNo (unique)Hash orderAvg O(1)Visited URLs, seen IDs

Differences between set, multiset, unordered_set

  • Same “collection of keys” idea — different uniqueness and ordering contracts.
Featuresetmultisetunordered_set
DuplicatesNoYesNo
OrderSortedSortedUnspecified
StructureTreeTreeHash table
insert/findO(log n)O(log n)Avg O(1)
count(k)0 or 1Frequency0 or 1
erase(k)That key**All** equalsThat key
Real-lifeUnique sorted IDsSorted bag of scoresFast “seen?” set
Need sorted walk?YesYesNo

set — unique sorted keys

  • Stores **unique** keys in **sorted** order (balanced tree).
  • insert / find / erase are **O(log n)**.
  • Inserting an existing key has no effect (set stays unique).
  • Iterators walk keys in ascending order.
  • **Real-life:** classroom roll numbers (no duplicates, naturally sorted); sorted unique product SKUs on a shelf list.
#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {3, 1, 2, 2}; // {1, 2, 3}
    s.insert(4);
    cout << s.count(2) << "\n"; // 1
    for (int x : s) cout << x << " ";
    cout << "\n";
    return 0;
}

multiset — sorted with duplicates

  • Like set, but **duplicate keys are allowed** and kept sorted.
  • count(key) returns how many times the key appears.
  • equal_range(key) gives the iterator range of all equal keys.
  • erase(key) removes **all** matches; erase(iterator) removes one.
  • **Real-life:** exam marks where several students score 90; waiting times logged and sorted with repeats.
#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> ms = {1, 2, 2, 3};
    ms.insert(2); // now three 2's
    cout << ms.count(2) << "\n"; // 3
    auto [lo, hi] = ms.equal_range(2);
    for (auto it = lo; it != hi; ++it) cout << *it << " ";
    cout << "\n";
    return 0;
}

unordered_set — unique hashed keys

  • Unique keys; **not sorted** — hash buckets.
  • Average **O(1)** insert/find/erase; worst case can degrade.
  • Great for membership tests (“have I seen this before?”).
  • Custom types need a **hash** and **equality**.
  • **Real-life:** airport boarding pass scan (already boarded?); unique words in a document when order does not matter.
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;

int main() {
    unordered_set<string> us = {"a", "b"};
    us.insert("c");
    us.insert("a"); // ignored — unique
    cout << (us.find("a") != us.end()) << "\n"; // 1
    cout << us.size() << "\n"; // 3
    return 0;
}

Common operations

  • Shared ideas: insert, erase, find, count, size, empty, iterate with range-for.
  • find returns an iterator; compare with end() for missing keys.
  • Prefer count/find over assuming sorted order on unordered_set.
Operationset / multisetunordered_set
Insertinsert(x)insert(x)
Lookupfind / count O(log n)find / count avg O(1)
IterateAscending keysBucket order (unspecified)
Duplicatesset no / multiset yesNo
Lower/upper boundYes (tree)No

Real-life examples by container

  • Map everyday problems to the right set type.
Real-life situationBest fitWhy
Unique student roll numbers, sorted printoutsetUnique + ascending order
Tags on a blog post (no duplicate tags)setUniqueness + optional sorted display
Dictionary of banned words (lookup often)unordered_setFast membership, order unused
“Visited page” tracker in a crawlerunordered_setFast “seen URL?” checks
Exam scores with many 85s and 90smultisetDuplicates + sorted
Sensor readings bag, keep all repeats sortedmultisetMulti + order
Lottery ticket numbers (unique draws)setUnique sorted set
Login session tokens already usedunordered_setO(1) replay check
Sorted unique product IDs for inventorysetOrdered unique catalog
Word frequency prep (count later in map)multiset or mapMulti if only bag; map if count

Set family applications

  • Sets appear whenever you track membership, uniqueness, or sorted bags of keys.
ApplicationContainerHow it helps
Remove duplicates from a listset / unordered_setInsert all; size is unique count
Membership / “seen before?”unordered_setAverage O(1) find/insert
Sorted unique reportsetIterate ascending unique keys
Frequency of equal keysmultisetcount / equal_range
Intersection of two ID listssetWalk both sorted ranges
Graph visited nodesunordered_setMark nodes as explored
Spell-check dictionaryunordered_setFast word present?
Leaderboard ties (same score many times)multisetKeep all equal scores sorted
Unique event IDs todaysetDedup + chronological-ish sort if numeric
Anagram helper (char multiset)multisetSame letters with counts

Application — unique sorted IDs (set)

  • **Real-life:** collect registration numbers; print once each in order.
#include <iostream>
#include <set>
#include <string>
using namespace std;

int main() {
    set<string> rolls;
    for (auto& id : {"A12", "B07", "A12", "C01"})
        rolls.insert(id);
    for (const auto& id : rolls) cout << id << " ";
    cout << "\n"; // A12 B07 C01
    return 0;
}

Application — exam scores bag (multiset)

  • **Real-life:** store every student’s mark; count how many scored 90.
#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> scores = {70, 90, 85, 90, 90, 60};
    cout << "How many 90s: " << scores.count(90) << "\n"; // 3
    cout << "Lowest: " << *scores.begin() << "\n";
    cout << "Highest: " << *scores.rbegin() << "\n";
    return 0;
}

Application — seen-before check (unordered_set)

  • **Real-life:** badge scanner — reject a second swipe of the same ID.
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;

int main() {
    unordered_set<string> seen;
    for (auto& id : {"U1", "U2", "U1", "U3"}) {
        if (!seen.insert(id).second)
            cout << id << " already entered\n";
        else
            cout << id << " welcome\n";
    }
    return 0;
}

When to use which

  • Need sorted unique keys or ordered traversal → **set**.
  • Need sorted keys **with duplicates** → **multiset**.
  • Need fast unique membership, order irrelevant → **unordered_set**.
  • **Real-life rule of thumb:** printer needs alphabetical unique list → set; hospital lab keeps all temperature readings → multiset; security gate only asks “seen?” → unordered_set.

Key points to remember

  • set = unique + sorted; multiset = duplicates + sorted; unordered_set = unique + hash.
  • multiset.erase(key) removes **all** equals — erase one iterator to remove a single copy.
  • unordered_set iteration order is not sorted and not stable across runs.
  • Use find/count for membership; do not assume hash order.
  • Real-life: unique IDs → set/unordered_set; score bags → multiset; fast seen? → unordered_set.
L2

Advanced — set / multiset / unordered_set

erase details on multiset

  • ms.erase(2) removes every 2.
  • To remove one duplicate: auto it = ms.find(2); if (it != ms.end()) ms.erase(it);.
  • **Real-life:** cancel one of three identical print jobs — erase by iterator, not by value.

Application — set intersection idea

  • Two sorted unique lists → walk with two iterators or use std::set_intersection.
  • **Real-life:** students in both “Math club” and “Robotics club”.
#include <iostream>
#include <set>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
    set<int> a = {1, 2, 3, 5};
    set<int> b = {2, 3, 4, 6};
    vector<int> both;
    set_intersection(a.begin(), a.end(), b.begin(), b.end(),
                     back_inserter(both));
    for (int x : both) cout << x << " ";
    cout << "\n"; // 2 3
    return 0;
}

Application — remove duplicates from stream

  • Insert into unordered_set (or set if you need sorted unique output).
  • **Real-life:** dedupe phone numbers from a CSV import.
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;

int main() {
    vector<int> raw = {5, 1, 5, 2, 1, 3};
    unordered_set<int> uniq;
    vector<int> out;
    for (int x : raw)
        if (uniq.insert(x).second) out.push_back(x);
    for (int x : out) cout << x << " ";
    cout << "\n"; // 5 1 2 3 (first-seen order)
    return 0;
}

Custom order / hash notes

  • set / multiset accept a comparator type (default less).
  • unordered_set may need std::hash specialization for user types.
  • Do not store mutable keys that change their hash/order while inside the container.
  • **Real-life:** descending leaderboard keys → set with greater<>; custom EmployeeId type needs hash for unordered_set.

Complexity reminder

  • Tree sets: predictable O(log n).
  • Hash sets: average O(1), watch pathological collisions and rehash cost.
  • Prefer unordered_set for pure membership; prefer set when you need order or ordered algorithms.

Design tips

  • Need order → tree (set/multiset); only membership → unordered_set.
  • Duplicates matter → multiset (or map key→count).
  • For “key → value”, use map / unordered_map, not a set.
  • Guard *find / *begin — empty containers have no elements.
  • Document real-life meaning of each key (ID, score, token).
L3

Tricky Interview Points

Q1) Difference between set and multiset?

Answer set stores unique sorted keys; multiset allows duplicate keys, still sorted.

Q2) set vs unordered_set?

Answer set is ordered (tree, O(log n)); unordered_set is hashed (average O(1)), no sorted order.

Q3) How do you remove one duplicate from a multiset?

Answer Erase a single iterator from find(), not erase(key) which removes all equals.

Q4) Can set store duplicates?

Answer No. Inserting an existing key does not add another element.

Q5) When prefer unordered_set?

Answer When you only need fast unique membership and do not need sorted iteration.

Q6) Give a real-life example for set.

Answer Unique student roll numbers printed in sorted order; unique product SKUs in a catalog.

Q7) Give a real-life example for multiset.

Answer Exam scores where many students share the same mark; a bag of sorted sensor readings.

Q8) Give a real-life example for unordered_set.

Answer Visited URLs in a crawler; badge IDs already scanned at a gate.

Q9) What does count return on set vs multiset?

Answer On set: 0 or 1. On multiset: how many times the key appears.

Q10) Default order of set?

Answer Ascending (less<T>). Use greater<T> for descending.

Q11) Can you lower_bound on unordered_set?

Answer No — ordered bounds are for tree containers (set/multiset/map).

Q12) set vs map?

Answer set stores keys only; map stores key→value pairs.

L4

Simple Programs

set — unique sorted

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {5, 1, 3, 3};
    for (int x : s) cout << x << " ";
    cout << "\n";
    return 0;
}

multiset — count duplicates

#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> ms = {1, 2, 2, 2, 4};
    cout << ms.count(2) << "\n";
    return 0;
}

unordered_set — membership

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    unordered_set<int> seen;
    for (int x : {1, 2, 1, 3}) {
        if (!seen.insert(x).second) cout << x << " duplicate\n";
    }
    return 0;
}

Real-life — unique tags (set)

#include <iostream>
#include <set>
#include <string>
using namespace std;

int main() {
    set<string> tags;
    for (auto& t : {"cpp", "stl", "cpp", "set"})
        tags.insert(t);
    for (const auto& t : tags) cout << "#" << t << " ";
    cout << "\n";
    return 0;
}

Real-life — score frequencies (multiset)

#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> marks = {88, 90, 88, 70, 90};
    for (int m : {70, 88, 90})
        cout << m << " appears " << marks.count(m) << "\n";
    return 0;
}

Real-life — gate scanner (unordered_set)

#include <iostream>
#include <unordered_set>
#include <string>
using namespace std;

int main() {
    unordered_set<string> inside;
    auto swipe = [&](const string& id) {
        if (inside.count(id)) cout << id << " already inside\n";
        else { inside.insert(id); cout << id << " entered\n"; }
    };
    swipe("A1"); swipe("B2"); swipe("A1");
    return 0;
}
L5

Problem Solving Tricks

  • set = unique + sorted; multiset = duplicates + sorted; unordered_set = unique + hash.
  • multiset.erase(key) removes ALL matches.
  • unordered_set has no meaningful sorted order.
  • Use count/find for membership tests.
  • Pick unordered_set for fast “seen before?” checks.
  • Pick set when you need ordered unique keys.
  • Real-life: rolls/tags → set; scores bag → multiset; visited IDs → unordered_set.
  • set ≠ map — no mapped value on set.
  • insert().second tells you if a new unique key was added.
  • rbegin() on set/multiset gives largest key quickly.
  • Prefer unordered_set for pure membership speed.
  • Document what each key means in the real problem.
L6

Practice Programs List

  1. Build a set from an array with duplicates; print sorted unique values.
  2. Use multiset to store scores and print how many times 90 appears.
  3. Use unordered_set to detect the first duplicate in a stream of ints.
  4. Compare sizes of set vs multiset filled with the same input.
  5. Write a short table: when you would choose each of the three.
  6. Model blog tags with a set of strings (no duplicate tags).
  7. Model a badge gate with unordered_set; reject second swipe.
  8. Erase only one copy of a score from a multiset of marks.
  9. Compute intersection of two club membership sets.
  10. List 8 real-life examples and pick the best container for each.
  11. Explain why erase(key) on multiset is dangerous for “cancel one job”.
  12. Deduplicate a CSV of phone numbers preserving first-seen order.