Last 30 Days
No notifications
The and headers give you ~100 free functions that work on any container with iterators. Master a dozen and you'll write less, faster, clearer code.
#include <algorithm>
#include <numeric>
using namespace std;vector<int> v{3, 1, 4, 1, 5, 9, 2, 6};
sort(v.begin(), v.end()); // 1, 1, 2, 3, 4, 5, 6, 9
sort(v.begin(), v.end(), greater<int>()); // descending
bool found = binary_search(v.begin(), v.end(), 5);
auto it = find(v.begin(), v.end(), 4);
int sum = accumulate(v.begin(), v.end(), 0);
int evens = count_if(v.begin(), v.end(), [](int x){ return x % 2 == 0; });
bool any = any_of(v.begin(), v.end(), [](int x){ return x > 5; });
bool all = all_of(v.begin(), v.end(), [](int x){ return x > 0; });
transform(v.begin(), v.end(), v.begin(), [](int x){ return x * x; });
reverse(v.begin(), v.end());
auto [mn, mx] = minmax_element(v.begin(), v.end());
#include <ranges>
namespace rv = std::views;auto squared_evens = v
| rv::filter([](int x){ return x % 2 == 0; })
| rv::transform([](int x){ return x * x; });
for (int x : squared_evens) cout << x << ' ';
Algorithms work on iterator pairs [begin, end) — half-open. They don't know or care which container you have, only that you can step through it.
| Group | Examples |
| Non-modifying | find, count, any_of, all_of, equal, mismatch |
| Modifying | copy, transform, replace, fill, generate |
| Removing | remove, unique (use erase-remove idiom) |
| Sorting | sort, stable_sort, partial_sort, nth_element |
| Binary search | binary_search, lower_bound, upper_bound (need sorted) |
Numeric () | accumulate, reduce, partial_sum, iota, gcd |
| Min/max | min, max, minmax, min_element, max_element |
| Heap | make_heap, push_heap, pop_heap |
sortsort(v.begin(), v.end()); // ascending
sort(v.begin(), v.end(), greater<int>()); // descending
sort(people.begin(), people.end(),
[](const Person& a, const Person& b){ return a.age < b.age; });std::sort is introsort — quicksort + heapsort fallback. Average and worst case O(n log n). Not stable. Use stable_sort (O(n log² n) worst) when equal keys must keep order.
sort(people.begin(), people.end(), [](const auto& a, const auto& b){
if (a.dept != b.dept) return a.dept < b.dept;
return a.salary > b.salary;
});find, find_ifauto it = find(v.begin(), v.end(), 7);
if (it != v.end()) cout << "found at index " << (it - v.begin());auto it2 = find_if(v.begin(), v.end(),
[](int x){ return x > 100; });
> Always compare with .end() — that's the "not found" sentinel.
count, count_ifint n_zeros = count(v.begin(), v.end(), 0);
int n_big = count_if(v.begin(), v.end(),
[](int x){ return x > 1000; });any_of, all_of, none_ofbool has_negative = any_of (v.begin(), v.end(), [](int x){ return x < 0; });
bool all_positive = all_of (v.begin(), v.end(), [](int x){ return x > 0; });
bool none_zero = none_of(v.begin(), v.end(), [](int x){ return x == 0; });These short-circuit — they stop as soon as the answer is decided.
transform — Mapvector<int> v{1, 2, 3, 4};
vector<int> squares(v.size());
transform(v.begin(), v.end(), squares.begin(),
[](int x){ return x * x; });
// squares: 1, 4, 9, 16// Two-input variant:
vector<int> a{1,2,3}, b{10,20,30}, sums(3);
transform(a.begin(), a.end(), b.begin(), sums.begin(), plus<>{});
// sums: 11, 22, 33
accumulate, reduce — Fold#include <numeric>
int total = accumulate(v.begin(), v.end(), 0);
int product = accumulate(v.begin(), v.end(), 1, multiplies<int>());string joined = accumulate(words.begin(), words.end(), string{},
[](const string& acc, const string& w){
return acc.empty() ? w : acc + ", " + w;
});
std::reduce (C++17) is like accumulate but allows parallel/unordered execution.
copy, copy_ifvector<int> evens;
copy_if(v.begin(), v.end(),
back_inserter(evens),
[](int x){ return x % 2 == 0; });back_inserter (from ) appends to evens via push_back.
remove + erase — The Erase-Remove Idiomstd::remove does not actually remove anything from a vector. It shuffles "kept" elements forward and returns the new logical end. You then erase from there to the real end.
v.erase(remove(v.begin(), v.end(), 3), v.end()); // remove all 3sv.erase(remove_if(v.begin(), v.end(),
[](int x){ return x < 0; }),
v.end()); // drop negatives
C++20 simplifies this to std::erase / std::erase_if:
erase(v, 3);
erase_if(v, [](int x){ return x < 0; });unique — Collapse Adjacent DuplicatesRequires the range to be sorted (or at least: duplicates already adjacent).
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); // dedupe| Algorithm | Returns |
binary_search | bool — present or not |
lower_bound | iterator to first >= value |
upper_bound | iterator to first > value |
equal_range | pair {lower, upper} |
sort(v.begin(), v.end());
auto it = lower_bound(v.begin(), v.end(), 5);
if (it != v.end() && *it == 5)
cout << "found 5 at index " << (it - v.begin());int a = min({3, 1, 4, 1, 5, 9});
auto [it_lo, it_hi] = minmax_element(v.begin(), v.end());
cout << "min=" << *it_lo << " max=" << *it_hi;vector<int> v(10);
iota(v.begin(), v.end(), 1); // 1, 2, 3, ..., 10
int s = accumulate(v.begin(), v.end(), 0); // 55vector<int> psum(v.size());
partial_sum(v.begin(), v.end(), psum.begin()); // 1, 3, 6, 10, ...
cout << gcd(12, 18); // 6
cout << lcm(4, 6); // 12
The classic algorithms work great but the iterator-pair style is verbose. Ranges fix that:
#include <ranges>
namespace rv = std::views;
namespace ra = std::ranges;vector<int> v{1, 2, 3, 4, 5};
// Pipeline: filter | transform
auto result = v
| rv::filter([](int x){ return x % 2 == 0; })
| rv::transform([](int x){ return x * x; });
// Lazy! Materialise:
vector<int> out(result.begin(), result.end()); // {4, 16}
ra::sort(v); // no .begin()/.end() needed
ra::find(v, 3);
Treat ranges as "the modern way" — but the classic algorithms aren't going anywhere.
Most STL algorithms take a callable. Lambdas keep the logic local:
sort(people.begin(), people.end(),
[](const Person& a, const Person& b){ return a.age < b.age; });count_if(v.begin(), v.end(), [](int x){ return x > threshold; });
Capture by value [=], by reference [&], or specifically [threshold].
| Bug | Fix | |||
remove(v.begin(), v.end(), x); doesn't shrink the vector | Pair with v.erase(...) or use C++20 std::erase | |||
binary_search on unsorted range | Sort first | |||
Off-by-one with end() (it points past last) | Always compare it != v.end() | |||
| Iterator invalidation during loop | Re-fetch iterators after push_back etc. | Cheat-Sheet | Verb | Algorithm |
| Sort | sort, stable_sort, partial_sort | |||
| Find | find, find_if, binary_search, lower_bound | |||
| Count | count, count_if | |||
| Test all/any | all_of, any_of, none_of | |||
| Map | transform | |||
| Fold | accumulate, reduce | |||
| Filter & copy | copy_if, remove_copy_if | |||
| In-place delete | erase-remove idiom, C++20 erase_if | |||
| Min/max | min_element, max_element, minmax | |||
| Range pipeline | v \ | views::filter \ | views::transform |
You can now express most data manipulation as a one-liner. Iterators next — the glue that makes all of this work.