5.2.19 · D4 · HinglishC++ Programming

ExercisesSTL containers — vector, list, deque, array, set, multiset, map, multimap, unordered_map, unordered_set

2,505 words11 min read↑ Read in English

5.2.19 · D4 · Coding › C++ Programming › STL containers — vector, list, deque, array, set, multiset,

Poore note mein, matlab container mein currently kitne elements hain. "Cost" ka matlab hamesha yahi hai ki running time ke saath kaise badhta hai — agar yeh phrase naya lagta hai toh Big-O notation dekho.


Level 1 — Recognition

(Kya tum sahi tool aur uski headline cost naam kar sakte ho?)

Exercise 1.1

Har zaroorat ke liye, ek best STL container batao: (a) 30-element lookup table jiska size ek fixed compile-time constant hai. (b) Pixels ki ek growable list jisme tum sirf push_back karte ho aur position se index karte ho. (c) string → int ka ek dictionary jisme entries ko alphabetical order mein print karna zaroori ho. (d) Ek collection jisme tum utni hi baar push_front aur push_back karte ho.

Recall Solution

(a) ==std::array<T, 30> — fixed size compile time pe pata hai, stack pe rehta hai, zero overhead. (b) std::vector== — contiguous, index v[i], amortised push_back. (c) ==std::map<string,int>== — tree-based, toh iteration sorted key order mein free mein hoti hai. (d) ==std::deque== — yeh akela sequence container hai jisme dono ends pe amortised milta hai.

Inhe swap kyun nahi karna? (d) ke liye vector pe per push_front lagta hai kyunki har element ko ek slot right shift karna padta hai. (c) ke liye unordered_map arbitrary bucket order mein print karega — iske paas koi ordering nahi hai.

Exercise 1.2

Blanks ko , , ya se bharo: vector random access = ____; list random access = ____; set search = ____; unordered_set search (average) = ____.

Recall Solution
  • vector random access: ==== — base pointer pe ek multiply-and-add.
  • list random access: ==== — nodes bikre hue hain, tumhe next pointers walk karne padte hain.
  • set search: ==== — ek balanced red-black tree har level pe search space half kar deta hai.
  • unordered_set search (average): ==== — ek hash seedha bucket pe jump karta hai.

Level 2 — Application

(Rules plug in karo aur costs compute karo.)

Exercise 2.1

Ek vector<int> khali start hoti hai. Tum exactly baar push_back call karte ho. Doubling strategy (capacity ) use karke, resizes ke dauran total kitne element copies hote hain, aur kya yeh hai?

Recall Solution

Resizes sizes (woh powers of two ) se theek pehle trigger hote hain. Capacity se resize pe tum existing elements copy karte ho. Total copies: Yeh sum kyun? Geometric series . Yahaan , toh . , toh copy work hai. pushes mein spread karo ⇒ , yaani amortised ==== per push. Dekho Amortised analysis.

Exercise 2.2

Tum insertions ek container mein karoge aur phir ek full iteration sorted order mein. map vs unordered_map ka total asymptotic cost compare karo (assume karo ki unordered_map ki keys alag se sort karni padengi, mein).

Recall Solution
  • map: har insert total; iteration already sorted, . Grand total ====.
  • unordered_map: inserts average, lekin sorted output ke liye keys copy karo aur sort karo: . Grand total ==== bhi.

Conclusion: same asymptotic class. map simplicity mein jeetra hai (order free hai), jabki unordered_map raw insert speed mein jeet sakta hai lekin phir sort ka daam chukana padta hai. Koi bhi "hamesha faster" nahi hai.


Level 3 — Analysis

(Diagnose karo ki ek design slow ya galat kyun hai.)

Exercise 3.1

Ek student ek vector<int> ko sorted rakhta hai aur, incoming numbers mein se har ek ke liye, binary search se dhundhe gaye correct sorted position pe insert karta hai. Total cost kya hai, aur kaun sa container fix karta hai?

Figure — STL containers — vector, list, deque, array, set, multiset, map, multimap, unordered_map, unordered_set
Recall Solution

Slot dhundne ke liye binary search hai — sasta. Lekin vector ke middle mein insert karne se uske baad wala har element ek slot right shift hota hai: har insert pe copies tak (figure mein orange shifted block dekho). inserts ke baad: Binary search tumhe save nahi kartashift dominate karta hai. Fix: ek ==std::multiset== (tree-based). Har insert hai placement samet, total , aur yeh duplicates ke saath sorted rehta hai.

Exercise 3.2

unordered_map worst case mein per lookup tak kyun degrade ho sakta hai, jabki map kabhi nahi karta?

Recall Solution

Ek unordered_map keys ko ek hash function ke zariye buckets mein scatter karta hai. Agar bahut saari keys ek bucket mein collide ho jayein, woh bucket length tak ki linked chain ban jaati hai; ek lookup ko poori chain scan karni padti hai — . Yeh bure hash ya adversarial input set ke saath hota hai. Ek map ek red-black tree hai jiska height guaranteed hai balancing rules ki wajah se, toh search hamesha hai — koi worst case darne wala nahi. Tradeoff: average hash ke average se slower hai jab hash theek behave kare.


Level 4 — Synthesis

(Ek poora solution banao, containers deliberately choose karke.)

Exercise 4.1

words ki ek stream di gayi hai, har distinct word ko uski count ke saath decreasing frequency order mein print karo (ties alphabetically break honge). Kaun se containers, aur total cost kya?

Recall Solution

Do phases:

  1. Count ek ==unordered_map<string,int>== se — freq[w]++ average hai, total .
  2. Rank karo pairs ko ek vector<pair<string,int>> mein move karke aur custom comparator se sort karke: pehle higher count, ties pe alphabetical. distinct words sort karna hai.
unordered_map<string,int> freq;
for (auto& w : words) freq[w]++;
vector<pair<string,int>> v(freq.begin(), freq.end());
sort(v.begin(), v.end(), [](auto& a, auto& b){
    if (a.second != b.second) return a.second > b.second; // count desc
    return a.first < b.first;                             // word asc
});
for (auto& [w,c] : v) cout << w << " " << c << "\n";

Yeh split kyun? Counting ko raw lookup speed chahiye (koi order nahi) → hash map. Ranking ko ek custom order chahiye jo hash map provide nahi kar sakta → vector mein dump karo aur sort karo. Total ====, aur kyunki hai toh yeh hai. std::sort use karta hai.

Exercise 4.2

Integers ka ek running collection maintain karo jo support kare: insert(x), erase one copy of x, aur query the current median. Kaun sa/se container(s)?

Recall Solution

Do multiset<int> halves use karo: lo (chhota half, jiska sabse bada *lo.rbegin() hai) aur hi (bada half, jiska sabse chhota *hi.begin() hai). Sizes balanced rakho taaki lo mein hi ke barabar ya exactly ek zyada count ho.

  • Insert: x ko lo ya hi mein daalo current median se compare karke, phir rebalance karo ek boundary element ko doosri taraf move karke agar sizes 2 se differ karein. Har step hai.
  • Erase one copy: s.erase(s.find(x)) — note karo ki find ek iterator deta hai toh sirf ek copy remove hoti hai; erase(x) saari copies wipe kar deta (yahi L5 trap neeche hai). .
  • Median: agar sizes equal hain, *lo.rbegin() aur *hi.begin() ka average; warna *lo.rbegin(). .

multiset kyun, set nahi? Duplicates store hone chahiye — same integer kai baar aa sakta hai. Saare ops ==== hain.


Level 5 — Mastery

(Subtle semantics aur invalidation traps.)

Exercise 5.1

multiset<int> ms = {5,5,5,7}; Predict karo size kya hogi (a) ms.erase(5); ke baad aur (b) ms.erase(ms.find(5)); ke baad.

Recall Solution

Starting size = 4. (a) ms.erase(5) ek value pass karta hai ⇒ har 5 remove ho jaata hai. Teen panchon gone. Size = ==== (sirf 7). (b) ms.erase(ms.find(5)) ek 5 ke iterator ko pass karta hai ⇒ exactly ek element remove hota hai. Size = ==== (do 5 aur ek 7).

Rule: value-erase saare matches delete karta hai; iterator-erase sirf ek delete karta hai.

Exercise 5.2

vector<int> v = {1,2,3};
v.reserve(3);                 // capacity now 3, size 3
int* p = &v[0];
v.push_back(4);               // triggers reallocation
cout << *p;                   // ??

Kya *p padhna safe hai? Explain karo.

Recall Solution

Nahi — yeh undefined behaviour hai. Vector full tha (capacity 3, size 3), toh push_back(4) ek naya, bada block allocate karta hai, 1,2,3,4 usmein copy karta hai, aur purana block free kar deta hai. p abhi bhi freed purani memory ki taraf point karta hai — yeh ek dangling pointer hai. *p padhne se 1, garbage, ya crash ho sakta hai. Fix: kisi bhi insertion ke baad re-fetch karo jo reallocate kar sakta ho, ya pehle se itna reserve karo ki jab tak p hold karo koi reallocation na ho. Dekho Iterators in C++ — same invalidation iterators aur references pe bhi apply hoti hai.

Exercise 5.3

Tumhe same live data pe key se average lookup aur sorted order mein keys iterate karne ki zaroorat hai. Kya ek single standard container dono kar sakta hai? Sahi design kya hai?

Recall Solution

Koi single standard container dono nahi deta. unordered_map lookup deta hai lekin koi order nahi; map sorted iteration deta hai lekin lookup. Tumhe ek primary structure choose karni hogi:

  • Agar lookups ordered scans se kahin zyada hain → unordered_map rakho, aur jab kabhi sorted output chahiye, keys ko vector mein copy karo aur sort karo (, rarely hota hai).
  • Agar ordered iteration frequent hai → map use karo aur lookups accept karo.

Koi free lunch nahi hai: parent note ka EK idea — har container ek chosen tradeoff hai — yahi forbid karta hai ek container jo simultaneously unordered-fast aur order-preserving ho.


Recall Self-test checklist

Main ek given access pattern ke liye sahi container naam kar sakta hoon ::: L1 done Main doubling amortise kar sakta hoon aur pushes ke liye copies nikaal sakta hoon ::: L2 done Main explain kar sakta hoon ki sorted-vector insert kyun hai aur multiset kyun fix karta hai ::: L3 done Main pe two-multiset median tracker design kar sakta hoon ::: L4 done Main value-erase vs iterator-erase aur reallocation pe pointer invalidation jaanta hoon ::: L5 done