Exercises — STL algorithms — sort, find, transform, accumulate, copy, all_of, any_of
5.2.20 · D4· Coding › C++ Programming › STL algorithms — sort, find, transform, accumulate, copy, al

Figure: baayi taraf ek source range ek algorithm ke through ek sink mein jaata hai. v.begin() fixed slots overwrite karta hai (jagah chahiye); back_inserter(w) nayi slots append karta hai (badhta hai). Isliye ek empty destination ko funnel ki zaroorat hai.
Level 1 — Recognition
Tumhe ek sentence plain English mein diya gaya hai. Tumhara kaam sirf itna hai: ek STL algorithm ka naam batao jo ise express kare, aur batao ki wo kya return karta hai.
Exercise 1.1 (L1)
"Ek vector<int> mein numbers ko increasing order mein rakh do." Kaun sa algorithm, aur wo kya return karta hai?
Recall Solution 1.1
Algorithm: ==sort== — specifically sort(v.begin(), v.end()).
Returns: kuch nahi (void). Ye elements ko in place rearrange karta hai; container khud result hai.
Baaki kyun nahi? find ek element locate karta hai, transform ek function map karta hai, copy duplicate karta hai — inme se koi bhi reorder nahi karta. Sirf sort hi ek range ko reorder karta hai.
Exercise 1.2 (L1)
"Mujhe batao ki har student ka score kam se kam 40 hai ya nahi." Kaun sa algorithm?
Recall Solution 1.2
Algorithm: ==all_of== with predicate [](int s){ return s >= 40; }.
Returns: ek bool. true sirf tab jab har element pass kare; ek empty vector pe ye true return karta hai (vacuous truth — koi failing student exist nahi karta).
any_of ye answer deta ki "kya kam se kam ek passer hai", jo alag sawaal hai.
Level 2 — Application
Ab actual call likho / trace karo aur exact result do.
Exercise 2.1 (L2)
vector<int> v{5, 2, 8, 1, 9, 3}; diya hai, ise lambda ke saath descending sort karo. Call likho aur final vector do.
Recall Solution 2.1
#include <vector>
#include <algorithm>
using namespace std;
// ...
sort(v.begin(), v.end(), [](int a, int b){ return a > b; });
// v = {9, 8, 5, 3, 2, 1}a > b kyun? Comparator cmp(a,b) ko true return karna chahiye jab a ko b se pehle aana chahiye. "Bada pehle aata hai" exactly a > b hai, jo descending order deta hai. Default operator< ascending deta hai. Neeche comparator figure dekho.

Figure: comparator ek yes/no gate hai. cmp(a,b) = "kya a ko b se pehle baithna chahiye?" a < b ke saath (teal) chhoti values front jeetti hain → ascending. a > b ke saath (orange) badi values front jeetti hain → descending.
Exercise 2.2 (L2)
vector<double> v{1.5, 2.5, 3.0}; diya hai, sum sahi se compute karo. Agar tum accumulate(v.begin(), v.end(), 0) likhte ho toh kya galat hoga?
Recall Solution 2.2
#include <vector>
#include <numeric>
using namespace std;
// ...
double s = accumulate(v.begin(), v.end(), 0.0); // s == 7.00 ke saath bug: accumulator ka type init ke type ke barabar hota hai. int init = 0 ke saath, har partial sum ek int mein store hota hai:
(truncated), , . Tumhe 6 milta, 7.0 nahi.
Fix: 0.0 pass karo taaki accumulator double ho. Sahi total hai .
Exercise 2.3 (L2)
vector<int> v{1, 2, 3, 4, 5}; diya hai, ek nayi vector w banao jisme har element cubed ho, v ko change kiye bina. Call likho.
Recall Solution 2.3
#include <vector>
#include <algorithm>
#include <iterator> // <-- needed for back_inserter
using namespace std;
// ...
vector<int> w; // starts empty (size 0)
transform(v.begin(), v.end(),
back_inserter(w), // grows w via push_back (see funnel figure)
[](int x){ return x*x*x; });
// w = {1, 8, 27, 64, 125}back_inserter(w) kyun? transform dest mein assign karta hai; wo container ko grow nahi karta. Kyunki w empty hai, w.begin() kisi valid jagah point nahi karta. Ek back_inserter — jo <iterator> mein defined hai — har write ko ek push_back mein convert karta hai, w ko safely grow karta hai. Cubes: .
Level 3 — Analysis
Outputs predict karo aur subtle behaviour diagnose karo.
Exercise 3.1 (L3)
Ek empty vector pe any_of kya return karta hai, aur all_of kya return karta hai? Fold identities se samjhao.
Recall Solution 3.1
Empty range pe:
all_of→ ==true==. Yetruese AND-fold karta hai: . Koi element counterexample nahi ho sakta, isliye "all pass" vacuously hold karta hai.any_of→ ==false==. Yefalsese OR-fold karta hai: . Koi element nahi hai jo ise true kare. Mental model:all_ofhai identitytrueke saath;any_ofhai identityfalseke saath. Start value hi empty-range answer hai — fold figure dekho.

Figure: folding as a running box. all_of true se start karta hai aur har result ko AND-fold karta hai; any_of false se start karta hai aur OR-fold karta hai. Koi element nahi hone par box apna start value rakhta hai — wahi start value empty-range answer hai.
Exercise 3.2 (L3)
Ise trace karo. idx kya hai?
#include <vector>
#include <algorithm>
using namespace std;
// ...
vector<int> v{10, 20, 30, 40};
auto it = find(v.begin(), v.end(), 25);
size_t idx = it - v.begin();Recall Solution 3.2
25 v mein nahi hai, isliye find v.end() return karta hai — last element se ek aage. Tab
Toh idx == 4. Khatre ki baat: code ne pehle it != v.end() check nahi kiya. Silently 4 produce ho gaya, ek index jo real position jaisa lagta hai lekin actually "not found" sentinel hai jo number mein convert ho gaya. Dereference ya position measure karne se pehle hamesha if (it != v.end()) test karo.
Exercise 3.3 (L3)
accumulate(v.begin(), v.end(), 10, [](int a, int b){ return a - b; }) with v{1, 2, 3}. Result compute karo aur samjhao ki left-vs-right fold yahan kyun matter karta hai.
Recall Solution 3.3
accumulate ek left fold hai: ye op(acc, e) apply karta hai left se right chalte hue, init se start karke.
Result = 4.
Direction kyun matter karta hai: subtraction associative nahi hai. Ek right fold alag number deta (). Kyunki accumulate direction fix karta hai (left), op evaluate hota hai ((10-1)-2)-3 ki tarah. Jab bhi non-+ op pass karo, commutativity/associativity assume mat karo.
Level 4 — Synthesis
Ek kaam karne ke liye do ya zyada algorithms combine karo.
Exercise 4.1 (L4)
vector<int> v{4, 7, 2, 9, 5, 1} se, 4 se bade elements ka sum compute karo, transform + accumulate use karke (koi raw loop nahi). Code aur number do.
Recall Solution 4.1
Idea: har element ko khud map karo agar >4 ho, warna 0, phir sum karo.
#include <vector>
#include <algorithm> // transform
#include <numeric> // accumulate
#include <iterator> // back_inserter
using namespace std;
// ...
vector<int> masked;
transform(v.begin(), v.end(), back_inserter(masked),
[](int x){ return x > 4 ? x : 0; });
// masked = {0, 7, 0, 9, 5, 0}
int total = accumulate(masked.begin(), masked.end(), 0); // 21Rakhe gaye: . Sum .
Ye pipeline kyun? transform unhe elements ko zero kar deta hai jo hum nahi chahte (0 + ka identity hai, isliye wo sum mein vanish ho jaate hain), aur accumulate unhe fold karta hai. Alternatively ek custom op a + (b>4 ? b : 0) ke saath accumulate ek pass mein kaam karta hai — wahi answer, 21.
Exercise 4.2 (L4)
vector<int> v{3, 8, 3, 5, 8, 1} diya hai, ek sorted copy banao duplicates rakhe bina, v unchanged rakh ke. Phir jawab do: kya sorted copy non-decreasing order mein hai? Sorted copy do.
Recall Solution 4.2
#include <vector>
#include <algorithm> // copy, sort
#include <iterator> // back_inserter
using namespace std;
// ...
vector<int> s;
copy(v.begin(), v.end(), back_inserter(s)); // s is a copy of v (grows via push_back)
sort(s.begin(), s.end()); // sort the copy only
// s = {1, 3, 3, 5, 8, 8}, v unchangedSorted copy: {1, 3, 3, 5, 8, 8}.
"Sorted hai kya?" check true hai — sort ke baad by construction non-decreasing hai. v abhi bhi {3,8,3,5,8,1} ke barabar hai.
copy pehle kyun? sort in place mutate karta hai. Original preserve karne ke liye tumhe ek duplicate sort karna hoga; copy with back_inserter woh duplicate ek empty vector mein safely build karta hai.
Level 5 — Mastery
Ek chhota sa solution design karo aur saare cases aur cost ke baare mein correctness ke baare mein sochna.
Exercise 5.1 (L5)
Ek function bool isPalindromeDigits(int n) likho jo true return kare tab aur sirf tab jab ek non-negative n ke decimal digits aage se aur peeche se same padhein. Forward digit string aur ek reversed copy banao, phir std::equal se dono sequences compare karo (aur ek all_of-based version se cross-check karo). n = 0 handle karo. Time complexity batao. n = 12321 aur n = 12345 pe test karo.
Recall Solution 5.1
#include <string>
#include <algorithm> // copy, equal, all_of
#include <iterator> // back_inserter
using namespace std;
bool isPalindromeDigits(int n) {
string s = to_string(n); // "0" for n==0, never empty
string r; // reversed copy, built via back_inserter
copy(s.rbegin(), s.rend(), // rbegin/rend walk s backwards
back_inserter(r)); // append each char -> r is s reversed
// Forward aur reversed digit sequences ko element-by-element compare karo:
return equal(s.begin(), s.end(), r.begin()); // true iff every position matches
}std::equal(first1, last1, first2) dono ranges ko lockstep mein chalata hai aur true return karta hai tab aur sirf tab jab har corresponding elements ka pair equal ho — exactly wahi "aage se aur peeche se same padhna" test hai. Kyunki r s ka reverse hai, equal tab succeed karta hai jab s palindrome ho.
all_of-based cross-check (same idea by index): position i position d-1-i se match karni chahiye.
#include <numeric> // iota
#include <vector>
bool isPalDigits2(int n) {
string s = to_string(n);
size_t d = s.size();
vector<size_t> idx(d);
iota(idx.begin(), idx.end(), 0); // idx = {0,1,...,d-1}
return all_of(idx.begin(), idx.end(),
[&](size_t i){ return s[i] == s[d-1-i]; });
}all_of "kya character i character d-1-i ko mirror karta hai?" ko saare positions ke upar AND-fold karta hai — true sirf tab jab har mirror-pair match kare. Ek empty index list pe ye vacuously true hota, lekin to_string kabhi empty string nahi deta isliye hum wahan pahunch hi nahi sakte.
Test values:
n = 0→s = "0",r = "0"→equalek char compare karta hai, match →true.n = 12321→s = "12321",r = "12321"→true.n = 12345→s = "12345",r = "54321"→ pehla pair'1'vs'5'differ karta hai →false. Cost: maano = number of digits ().to_stringhai, reversedcopyhai,equalhai. Total — Time complexity Big-O dekho. Saare cases covered: single digit (hamesha true), even/odd digit counts (equaldono handle karta hai), leading-zero ki chinta (koi nahi — integers mein leading zeros nahi hote).
Exercise 5.2 (L5)
Tumhe confirm karna hai ki ek vector<int> v ek valid non-decreasing sorted sequence hai bina re-sort kiye (wo bugs chhupa deta). Adjacent index positions pe std::all_of par based ek check design karo. Ise {1, 3, 3, 5} aur {1, 3, 2, 5} pe apply karo.
Recall Solution 5.2
all_of ek time pe ek element dekhta hai, isliye hum ise har left-hand neighbour ka index dete hain aur predicate ko v[i] aur v[i+1] dono dekhne dete hain. Predicate sirf ek strict decrease pe fail karna chahiye:
#include <vector>
#include <algorithm> // all_of
#include <numeric> // iota
using namespace std;
bool sortedNondec(const vector<int>& v){
if (v.size() < 2) return true; // empty / single -> vacuously sorted
vector<size_t> idx(v.size() - 1); // one slot per adjacent pair
iota(idx.begin(), idx.end(), 0); // idx = {0,1,...,n-2}
return all_of(idx.begin(), idx.end(),
[&](size_t i){ return v[i] <= v[i+1]; }); // no descent
}all_of "kya har pair non-decreasing (v[i] <= v[i+1]) hai?" ko AND-fold karta hai — ye pehle descent pe short-circuit karta hai. Ye exactly wahi hai jo library ka is_sorted internally compute karta hai; yahan hum ise build karte hain taaki mechanism visible ho.
{1, 3, 3, 5}: pairs(1,3),(3,3),(3,5)sab<=satisfy karte hain (note3 <= 3true hai, equal neighbours allowed hain) →true.{1, 3, 2, 5}: pair(3,2)3 <= 2fail karta hai →all_offalsereturn karta hai. Cost: ek pass, predicate calls ⇒ , re-sorting ke se bahut sasta — aur ye disorder ko erase karne ki jagah detect karta hai. Edge cases: empty vector aur single elementtruereturn karte hain (v.size() < 2se guarded, vacuous "sorted" se match karta hai). Predicate mein<=(<nahi) use karna hi woh hai jo non-decreasing sequence mein equal adjacent values allow karta hai.
Recall One-line self-test recap
Empty range: all_of ::: true
Empty range: any_of ::: false
4-element vector pe find miss, phir it - begin() ::: 4 (size / end() position)
accumulate(v, 0.0) vs accumulate(v, 0) doubles pe ::: 0.0 precision rakhta hai; 0 har partial sum ko int mein truncate karta hai
copy/transform ke dauran ek empty destination ko kya grow karta hai? ::: back_inserter(dst) (<iterator> se) — ye har write ko push_back karta hai
Forward vs reversed digit sequence compare karo ::: std::equal(s.begin(), s.end(), r.begin())
Sort karne se pehle original preserve karo ::: copy (ya copy-construct) karo phir copy ko sort karo