Algorithms — Beyond std::sort
The Algorithm Philosophy
The <algorithm> header contains ~100 functions that operate on iterator ranges. They don't know about containers — they only speak iterators. This is the payoff of the iterator abstraction.
The Sorting Family
▶ std::sort Visualization
Watch elements get sorted step by step.
std::sort
Introsort (quicksort + heapsort fallback). Average O(n log n), requires Random Access iterators.
std::vector<int> v = {5, 2, 8, 1, 9};
std::sort(v.begin(), v.end()); // ascending
// With custom comparator — descending
std::sort(v.begin(), v.end(), std::greater<int>{});
std::stable_sort
Preserves relative order of equal elements. Uses merge sort internally — may allocate extra memory.
std::partial_sort
Sort only the first K elements — O(n log k) instead of O(n log n):
std::partial_sort(v.begin(), v.begin() + 3, v.end());
// First 3 elements are the smallest, in sorted order
std::nth_element
Rearranges so that element at the nth position is what would be there in a sorted sequence — O(n) average:
std::nth_element(v.begin(), v.begin() + 2, v.end());
// v[2] is now the median (for a 5-element vector)
Searching
Binary Search Family
All require the range to be sorted:
std::vector<int> v = {1, 3, 5, 7, 9, 11};
bool found = std::binary_search(v.begin(), v.end(), 7); // true
auto lo = std::lower_bound(v.begin(), v.end(), 5); // points to 5
auto hi = std::upper_bound(v.begin(), v.end(), 5); // points to 7
auto [a, b] = std::equal_range(v.begin(), v.end(), 5);
// a points to 5, b points to 7
std::find / std::find_if
auto it = std::find(v.begin(), v.end(), 7);
auto it2 = std::find_if(v.begin(), v.end(),
[](int x) { return x > 6; }); // first element > 6
Partitioning
std::partition rearranges elements so those satisfying a predicate come first:
▶ std::partition Animation
Partition: even numbers to the left, odd to the right.
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
auto pivot = std::partition(v.begin(), v.end(),
[](int x) { return x % 2 == 0; });
// Even numbers are before pivot, odd after
// pivot points to the first odd element
Heap Operations
STL heaps are max-heaps built on a vector (or any random-access container):
std::vector<int> v = {3, 1, 4, 1, 5, 9};
std::make_heap(v.begin(), v.end()); // O(n)
// v.front() is now the max: 9
v.push_back(10);
std::push_heap(v.begin(), v.end()); // O(log n)
std::pop_heap(v.begin(), v.end()); // moves max to back
v.pop_back(); // remove it
std::sort_heap(v.begin(), v.end()); // turns heap into sorted array
Numeric Algorithms
From <numeric>:
#include <numeric>
std::vector<int> v = {1, 2, 3, 4, 5};
int sum = std::accumulate(v.begin(), v.end(), 0); // 15
int product = std::accumulate(v.begin(), v.end(), 1,
std::multiplies<int>{}); // 120
// Prefix sums
std::vector<int> prefix(5);
std::partial_sum(v.begin(), v.end(), prefix.begin());
// prefix = {1, 3, 6, 10, 15}
// Inner product
std::vector<int> w = {2, 3, 4, 5, 6};
int dot = std::inner_product(v.begin(), v.end(), w.begin(), 0);
// 2 + 6 + 12 + 20 + 30 = 70
std::transform
Apply a function to every element and write results to an output range:
std::vector<int> src = {1, 2, 3, 4};
std::vector<int> dst(src.size());
std::transform(src.begin(), src.end(), dst.begin(),
[](int x) { return x * x; });
// dst = {1, 4, 9, 16}
The Remove-Erase Idiom
std::remove doesn't actually remove — it moves unwanted elements to the end and returns a new logical end. You must erase the tail:
std::vector<int> v = {1, 2, 3, 2, 5, 2};
auto new_end = std::remove(v.begin(), v.end(), 2);
v.erase(new_end, v.end());
// v = {1, 3, 5}
// C++20 one-liner:
std::erase(v, 2);
Summary
std::sortis just the beginning — learnpartial_sort,nth_element, andstable_sort.- Use binary search functions on sorted ranges for O(log n) lookups.
std::partitionis underrated and extremely useful.- The
<numeric>header has gems:accumulate,partial_sum,inner_product. - Master the remove-erase idiom (or just use C++20
std::erase).