C++ Useful Algorithms and Classes
- Description: A note on
std::initializer_listand the most useful<algorithm>and<numeric>functions - My Notion Note ID: K2A-B1-15
- Created: 2018-10-03
- Updated: 2026-02-28
- License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io
Table of Contents
- 1.
std::initializer_list - 2. Sorting and Partitioning
- 3. Searching
- 4. Non-Modifying Algorithms
- 5. Modifying Algorithms
- 6. Numeric Algorithms
- 7. Set and Heap Operations
For C++20 Ranges, views, projections, and std::span, see the dedicated note: C++ Ranges, Views, and Span.
1. std::initializer_list
std::initializer_list<T> (C++11, <initializer_list>) allows functions and constructors to accept brace-enclosed lists of values. It enables uniform initialization syntax.
#include <initializer_list>
#include <iostream>
#include <vector>
class DataSet {
std::vector<int> data_;
public:
DataSet(std::initializer_list<int> init) : data_(init) {}
DataSet& operator=(std::initializer_list<int> init) {
data_.assign(init.begin(), init.end());
return *this;
}
void print() const {
for (int x : data_) std::cout << x << " ";
std::cout << std::endl;
}
};
int main() {
DataSet ds = {1, 2, 3, 4, 5};
ds.print(); // 1 2 3 4 5
ds = {10, 20, 30};
ds.print(); // 10 20 30
return 0;
}
Key properties of initializer_list:
- Elements are always
const(you cannot modify them through the list). - Copying an
initializer_listdoes not copy the underlying elements (it is lightweight). - The underlying array has automatic storage duration (it is a temporary).
2. Sorting and Partitioning
The <algorithm> header provides the standard sorting suite. std::sort, std::stable_sort, std::partial_sort, and std::nth_element require random-access iterators. std::partition requires only forward iterators, and std::stable_partition requires bidirectional iterators.
std::sort(first, last, [cmp])— Introsort; O(n log n) average and worst case. Not stable.std::stable_sort(first, last, [cmp])— Preserves relative order of equal elements. O(n log² n) worst case.std::partial_sort(first, middle, last, [cmp])— Sort just enough so that[first, middle)holds the smallest elements in order. Useful for top-k.std::nth_element(first, nth, last, [cmp])— Partial sort that puts the kth element in its sorted position; everything before is ≤ and everything after is ≥. O(n) average. The fastest way to find a kth-order statistic.std::partition(first, last, pred)— Reorder so elements satisfyingpredcome first. Returns the partition point. Not stable.std::stable_partition(first, last, pred)— Stable variant.
#include <algorithm>
#include <vector>
std::vector<int> v = {5, 2, 8, 1, 9, 3, 7};
std::sort(v.begin(), v.end()); // 1 2 3 5 7 8 9
std::sort(v.begin(), v.end(), std::greater<int>()); // 9 8 7 5 3 2 1
// Top-3 smallest, in order, in [begin, begin+3)
std::partial_sort(v.begin(), v.begin() + 3, v.end());
// Find median in O(n) average
auto mid = v.begin() + v.size() / 2;
std::nth_element(v.begin(), mid, v.end());
3. Searching
For an unsorted range, use linear scans. For a sorted range, use binary searches.
std::find(first, last, value)— Linear search; returns iterator to first match orlast.std::find_if(first, last, pred)— Linear search by predicate.std::binary_search(first, last, value)—bool-only; returns true if value is present.std::lower_bound(first, last, value)— First position wherevaluecould be inserted without breaking order (i.e. first>= value).std::upper_bound(first, last, value)— First position strictly greater thanvalue.std::equal_range(first, last, value)— Pair of(lower_bound, upper_bound).
#include <algorithm>
#include <vector>
std::vector<int> v = {1, 2, 4, 4, 4, 5, 7};
auto it1 = std::lower_bound(v.begin(), v.end(), 4); // points to first 4
auto it2 = std::upper_bound(v.begin(), v.end(), 4); // points to 5
size_t count_of_4 = it2 - it1; // 3
4. Non-Modifying Algorithms
These read but do not write the range.
std::count(first, last, value),std::count_if(first, last, pred)— Count occurrences.std::all_of(first, last, pred),std::any_of(first, last, pred),std::none_of(first, last, pred)— Predicate quantifiers.std::for_each(first, last, fn)— Apply a function to each element. (In modern C++, prefer a range-basedforloop.)std::min_element(first, last, [cmp]),std::max_element(first, last, [cmp]),std::minmax_element(first, last, [cmp])— Extrema in O(n).std::equal(first1, last1, first2)— Check element-wise equality of two ranges.std::mismatch(first1, last1, first2)— Find first position where two ranges differ.
5. Modifying Algorithms
These write into a destination range.
std::copy(first, last, d_first),std::copy_if(first, last, d_first, pred)— Copy with optional filter.std::move(first, last, d_first)— Move (not copy) elements; leaves source elements in valid-but-unspecified state. Note this is the algorithm, notstd::movethe cast.std::transform(first, last, d_first, fn)— Applyfnand write the result; can take two input ranges and a binaryfn.std::fill(first, last, value),std::generate(first, last, fn)— Fill with a constant or generator.std::replace(first, last, old, new),std::replace_if(first, last, pred, new)— In-place replace.std::remove(first, last, value),std::remove_if(first, last, pred)— Erase-remove idiom: these functions return a new logical end; you must follow up withcontainer.erase(...)to actually shrink the container. (C++20 introducesstd::eraseandstd::erase_iffor containers, which combine the two steps.)std::reverse(first, last),std::rotate(first, middle, last)— Reorder in place.std::unique(first, last)— Removes consecutive duplicates; combine withstd::sortfirst if you need global uniqueness. Same erase-remove pattern asremove.
// Erase-remove idiom (pre-C++20)
v.erase(std::remove_if(v.begin(), v.end(),
[](int x) { return x % 2 == 0; }),
v.end());
// C++20 equivalent
std::erase_if(v, [](int x) { return x % 2 == 0; });
6. Numeric Algorithms
The <numeric> header provides reductions and prefix sums.
std::accumulate(first, last, init, [op])— Sequential reduction. Defaultopis+. For floats, beware that order matters.std::reduce(first, last, init, [op])— Likeaccumulatebut unsequenced (parallelizable). Requiresopto be associative and commutative.std::transform_reduce(first, last, init, reduce_op, transform_op)— Map-reduce in one pass.std::inner_product(first1, last1, first2, init)— Dot product.std::partial_sum(first, last, d_first)— Prefix sums.std::adjacent_difference(first, last, d_first)— Differences between adjacent elements.std::iota(first, last, value)— Fill withvalue, value+1, value+2, ....
#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
std::vector<int> ids(10);
std::iota(ids.begin(), ids.end(), 0); // 0, 1, 2, ..., 9
7. Set and Heap Operations
- Set operations (require sorted input ranges, output is also sorted):
std::set_union,std::set_intersection,std::set_difference,std::set_symmetric_difference,std::includes,std::merge. - Heap operations (operate on a
RandomAccessRangerepresenting a max-heap):std::make_heap,std::push_heap,std::pop_heap,std::sort_heap,std::is_heap,std::is_heap_until. These are the building blocks behindstd::priority_queue.
#include <algorithm>
#include <vector>
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
std::make_heap(v.begin(), v.end()); // max-heap
std::cout << v.front() << std::endl; // 9
v.push_back(10);
std::push_heap(v.begin(), v.end()); // re-sift after push_back
std::pop_heap(v.begin(), v.end()); // moves max to back
int max_val = v.back(); v.pop_back(); // 10
C++20 added a separate ranges library — std::ranges::sort(v)-style algorithm overloads, lazy view composition with |, projections, and std::span. Those topics live in their own note: C++ Ranges, Views, and Span.