Programming Language & Its Applications β Generic Programming and Exception Handling, NEC licence examination syllabus (Nepal Engineering Council).
Containers, iterators and algorithms β a library where any algorithm works with any container through one uniform interface.
std::sort knows nothing about vector, and vector knows nothing about sorting, yet they compose perfectly through iterators. That design won a Programming Language Achievement award and was copied into Java's Collections, .NET's LINQ, Python's itertools and Rust's Iterator trait. Search "Alexander Stepanov STL design philosophy" β his argument that algorithms should be specified by their requirements rather than their types is one of the most influential ideas in software design.#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#include <unordered_map>
#include <stack>
#include <queue>
#include <string>
template <typename C>
void show(const char *tag, const C &c) {
std::cout << " " << tag;
for (const auto &x : c) std::cout << x << " ";
std::cout << "\n";
}
int main() {
/* ---- vector: contiguous, index in O(1) ---- */
std::vector<int> v{40, 10, 30, 20};
v.push_back(50);
show("vector : ", v);
std::cout << " v[2]=" << v[2] << " size=" << v.size()
<< " capacity=" << v.capacity() << "\n";
/* ---- list: O(1) insert anywhere, no [] ---- */
std::list<int> l{3, 1, 2};
l.push_front(0);
l.sort(); /* member sort, not std::sort */
show("list sorted : ", l);
/* ---- deque: O(1) at BOTH ends ---- */
std::deque<int> d{5, 6};
d.push_front(4); d.push_back(7);
show("deque : ", d);
/* ---- set: unique + automatically SORTED ---- */
std::set<int> s{50, 20, 40, 20, 10, 40};
show("set (uniq) : ", s);
std::cout << " count(20)=" << s.count(20)
<< " (duplicates collapsed)\n";
/* ---- map: sorted key -> value ---- */
std::map<std::string,int> marks;
marks["Sita"] = 91;
marks["Ram"] = 87;
marks["Hari"] = 76;
marks["Ram"] = 88; /* overwrites */
std::cout << " map (sorted by key):\n";
for (const auto &[name, m] : marks)
std::cout << " " << name << " = " << m << "\n";
/* find vs operator[] β a crucial difference */
std::cout << " map size before lookup = " << marks.size() << "\n";
std::cout << " marks[\"Gita\"] = " << marks["Gita"]
<< " (INSERTED a default 0!)\n";
std::cout << " map size after = " << marks.size() << "\n";
std::cout << " find(\"Bikash\") == end()? "
<< std::boolalpha
<< (marks.find("Bikash") == marks.end())
<< " (no insertion)\n";
/* ---- unordered_map: hash, no ordering ---- */
std::unordered_map<std::string,int> um{
{"one",1},{"two",2},{"three",3}};
std::cout << " unordered_map (arbitrary order): ";
for (const auto &[k,val] : um) std::cout << k << "=" << val << " ";
std::cout << "\n";
/* ---- adaptors ---- */
std::stack<int> st;
for (int i = 1; i <= 4; i++) st.push(i);
std::cout << " stack (LIFO) : ";
while (!st.empty()) { std::cout << st.top() << " "; st.pop(); }
std::cout << "\n";
std::queue<int> qu;
for (int i = 1; i <= 4; i++) qu.push(i);
std::cout << " queue (FIFO) : ";
while (!qu.empty()) { std::cout << qu.front() << " "; qu.pop(); }
std::cout << "\n";
std::priority_queue<int> pq;
for (int x : {30, 10, 50, 20}) pq.push(x);
std::cout << " priority_queue: ";
while (!pq.empty()) { std::cout << pq.top() << " "; pq.pop(); }
std::cout << "\n";
return 0;
}
Output:
vector : 40 10 30 20 50
v[2]=30 size=5 capacity=8
list sorted : 0 1 2 3
deque : 4 5 6 7
set (uniq) : 10 20 40 50
count(20)=1 (duplicates collapsed)
map (sorted by key):
Hari = 76
Ram = 88
Sita = 91
map size before lookup = 3
marks["Gita"] = 0 (INSERTED a default 0!)
map size after = 4
find("Bikash") == end()? true (no insertion)
unordered_map (arbitrary order): three=3 two=2 one=1
stack (LIFO) : 4 3 2 1
queue (FIFO) : 1 2 3 4
priority_queue: 50 30 20 10
map["key"] insertion behaviour causes real bugs. A function that "just checks" whether a key exists using if (m[k] != 0) silently grows the map on every miss β turning a read-only lookup into a memory leak in a long-running loop. Use m.count(k), m.find(k), or C++20's m.contains(k).
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <string>
int main() {
std::vector<int> v{45, 12, 78, 3, 56, 91, 23, 67};
auto print = [&](const char *tag) {
std::cout << " " << tag;
for (int x : v) std::cout << x << " ";
std::cout << "\n";
};
print("original : ");
/* ---- sorting ---- */
std::sort(v.begin(), v.end());
print("sorted asc : ");
std::sort(v.begin(), v.end(), std::greater<int>());
print("sorted desc : ");
std::sort(v.begin(), v.end());
/* ---- searching ---- */
auto it = std::find(v.begin(), v.end(), 56);
std::cout << " find(56) at index "
<< std::distance(v.begin(), it) << "\n";
bool has = std::binary_search(v.begin(), v.end(), 67);
std::cout << " binary_search(67) = " << std::boolalpha
<< has << "\n";
/* ---- counting and testing with lambdas ---- */
int evens = std::count_if(v.begin(), v.end(),
[](int x){ return x % 2 == 0; });
std::cout << " count_if even = " << evens << "\n";
bool allPos = std::all_of(v.begin(), v.end(),
[](int x){ return x > 0; });
bool anyBig = std::any_of(v.begin(), v.end(),
[](int x){ return x > 90; });
std::cout << " all_of >0 = " << allPos
<< " any_of >90 = " << anyBig << "\n";
/* ---- accumulate and min/max ---- */
int sum = std::accumulate(v.begin(), v.end(), 0);
auto [mn, mx] = std::minmax_element(v.begin(), v.end());
std::cout << " sum=" << sum << " min=" << *mn
<< " max=" << *mx
<< " avg=" << double(sum)/v.size() << "\n";
/* ---- transform: map one range onto another ---- */
std::vector<int> sq(v.size());
std::transform(v.begin(), v.end(), sq.begin(),
[](int x){ return x * x; });
std::cout << " squares : ";
for (int x : sq) std::cout << x << " ";
std::cout << "\n";
/* ---- the ERASE-REMOVE idiom ---- */
/* remove_if only SHIFTS unwanted elements to the end
and returns the new logical end. erase() actually
shrinks the container. Calling remove_if alone is a
classic bug β the size does not change. */
auto newEnd = std::remove_if(v.begin(), v.end(),
[](int x){ return x < 50; });
std::cout << " after remove_if size is STILL "
<< v.size() << "\n";
v.erase(newEnd, v.end());
std::cout << " after erase size is " << v.size() << ": ";
for (int x : v) std::cout << x << " ";
std::cout << "\n";
/* ---- reverse and accumulate with a custom op ---- */
std::reverse(v.begin(), v.end());
long product = std::accumulate(v.begin(), v.end(), 1L,
[](long a, int b){ return a * b; });
std::cout << " reversed, product = " << product << "\n";
return 0;
}
Output:
original : 45 12 78 3 56 91 23 67
sorted asc : 3 12 23 45 56 67 78 91
sorted desc : 91 78 67 56 45 23 12 3
find(56) at index 4
binary_search(67) = true
count_if even = 3
all_of >0 = true any_of >90 = true
sum=375 min=3 max=91 avg=46.875
squares : 9 144 529 2025 3136 4489 6084 8281
after remove_if size is STILL 8
after erase size is 4: 56 67 78 91
reversed, product = 26631696
std::sort(v.begin(), v.end()) you write std::ranges::sort(v), and operations compose lazily with a pipe syntax: v | std::views::filter(isEven) | std::views::transform(square) β evaluated on demand, allocating nothing. That is the same design as Java Streams, LINQ and Rust iterators, arriving in C++ two decades after the STL proved the underlying idea. Search "C++20 ranges views tutorial"; it is the single biggest change to how STL code looks.vector O(1) index, list O(1) insert, map/set O(log n), unordered_map O(1) average. State the five iterator categories and that std::sort needs random access (so a list uses its own sort()). The map[] inserts on read trap and the erase-remove idiom are both excellent discriminating answers.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦