C++ course menu
C++ STL Algorithms: sort, find, count, accumulate, transform and More
Learn the most useful C++ <algorithm> and <numeric> functions: sort with custom comparators, stable_sort, find and find_if, count_if, any_of/all_of, min_element and max_element, accumulate, transform, remove_if with erase, binary_search, reverse, unique, and C++20 ranges.
On this page
The headers <algorithm> and <numeric> contain more than a hundred ready-made functions for sorting, searching, counting and transforming data. They are well tested, usually faster than hand-written loops, and they make your intent obvious: std::count_if says "count" far more clearly than a loop with a counter.
Most algorithms take a range as two iterators (begin, end), and many take a function, usually a short lambda, that says what to do with each element. Lambdas are covered fully in Lambdas; here you only need the basic form [](int x) { return x > 0; }.
Sorting#
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
void print(const std::vector<int>& v) {
for (int x : v) std::cout << x << ' ';
std::cout << '\n';
}
int main() {
std::vector<int> v = {42, 7, 19, 3, 25};
std::sort(v.begin(), v.end());
print(v);
std::sort(v.begin(), v.end(), std::greater<int>()); // descending
print(v);
}3 7 19 25 42
42 25 19 7 3Sorting with a custom rule#
Pass a comparator that returns true when the first argument should come before the second:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Student {
std::string name;
int marks;
};
int main() {
std::vector<Student> students = {{"Ravi", 85}, {"Asha", 92}, {"Meera", 85}, {"John", 78}};
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
if (a.marks != b.marks) return a.marks > b.marks; // higher marks first
return a.name < b.name; // then by name
});
for (const auto& s : students) std::cout << s.name << ' ' << s.marks << '\n';
}Asha 92
Meera 85
Ravi 85
John 78std::sort is O(n log n) but not stable: equal elements may change order. std::stable_sort keeps equal elements in their original order, which matters when sorting by one key after another.
Searching#
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {4, 9, -2, 7, -5, 12};
auto it = std::find(v.begin(), v.end(), 7);
std::cout << "7 at index " << (it - v.begin()) << '\n';
auto neg = std::find_if(v.begin(), v.end(), [](int x) { return x < 0; });
if (neg != v.end()) std::cout << "first negative: " << *neg << '\n';
std::cout << std::boolalpha;
std::cout << std::any_of(v.begin(), v.end(), [](int x) { return x > 10; }) << ' '
<< std::all_of(v.begin(), v.end(), [](int x) { return x > -10; }) << ' '
<< std::none_of(v.begin(), v.end(), [](int x) { return x == 0; }) << '\n';
}7 at index 3
first negative: -2
true true trueBinary search on sorted data#
On a sorted range, std::binary_search checks membership in O(log n), and std::lower_bound finds where a value is (or would be inserted):
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> sorted = {3, 8, 15, 23, 42, 57};
std::cout << std::boolalpha << std::binary_search(sorted.begin(), sorted.end(), 23) << '\n';
auto pos = std::lower_bound(sorted.begin(), sorted.end(), 20);
std::cout << "20 would go at index " << (pos - sorted.begin()) << ", before " << *pos << '\n';
}true
20 would go at index 3, before 23Counting, minimum and maximum#
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> marks = {56, 91, 78, 34, 88, 91};
std::cout << std::count(marks.begin(), marks.end(), 91) << '\n';
std::cout << std::count_if(marks.begin(), marks.end(), [](int m) { return m >= 75; }) << '\n';
auto [lo, hi] = std::minmax_element(marks.begin(), marks.end());
std::cout << "lowest " << *lo << ", highest " << *hi << '\n';
std::cout << "best at index " << (std::max_element(marks.begin(), marks.end()) - marks.begin()) << '\n';
}2
4
lowest 34, highest 91
best at index 1max_element returns an iterator to the first largest element. For just two or three values, use std::max(a, b) or std::min({a, b, c}).
Summing and combining: <numeric>#
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
int sum = std::accumulate(v.begin(), v.end(), 0);
long long product = std::accumulate(v.begin(), v.end(), 1LL, [](long long acc, int x) { return acc * x; });
std::vector<int> ids(5);
std::iota(ids.begin(), ids.end(), 101); // 101, 102, 103, ...
std::cout << sum << ' ' << product << ' ' << ids.front() << ".." << ids.back() << '\n';
}15 120 101..105Transforming#
std::transform applies a function to each element and writes the results, possibly into the same container:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<double> prices = {100, 250, 80};
std::vector<double> with_tax(prices.size());
std::transform(prices.begin(), prices.end(), with_tax.begin(), [](double p) { return p * 1.18; });
for (double p : with_tax) std::cout << p << ' ';
std::cout << '\n';
std::string s = "Hello";
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
std::cout << s << '\n';
}118 295 94.4
HELLORemoving elements#
std::remove_if does not shrink the container: it moves the kept elements to the front and returns where the "garbage" tail starts. Pair it with erase (the erase-remove idiom), or use C++20's std::erase_if, which does both:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> a = {5, -2, 8, -7, 3};
a.erase(std::remove_if(a.begin(), a.end(), [](int x) { return x < 0; }), a.end());
std::vector<int> b = {5, -2, 8, -7, 3};
std::erase_if(b, [](int x) { return x < 0; }); // C++20
for (int x : a) std::cout << x << ' ';
std::cout << "| ";
for (int x : b) std::cout << x << ' ';
std::cout << '\n';
}5 8 3 | 5 8 3Reverse, unique and more#
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {3, 1, 3, 2, 1, 3};
std::sort(v.begin(), v.end()); // 1 1 2 3 3 3
v.erase(std::unique(v.begin(), v.end()), v.end()); // remove adjacent duplicates
std::reverse(v.begin(), v.end());
for (int x : v) std::cout << x << ' ';
std::cout << '\n';
}3 2 1std::unique removes only adjacent duplicates, so sort first. Other useful algorithms: std::fill, std::copy, std::rotate, std::shuffle, std::partition, std::nth_element, and std::next_permutation.
C++20 ranges#
C++20 adds versions of the algorithms in the std::ranges namespace that take a whole container instead of two iterators, plus views that filter and transform lazily:
#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> v = {5, 2, 8, 1, 9, 4};
std::ranges::sort(v);
std::cout << "sorted: ";
for (int x : v) std::cout << x << ' ';
std::cout << '\n';
auto even_squares = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; });
std::cout << "even squares: ";
for (int x : even_squares) std::cout << x << ' ';
std::cout << '\n';
}sorted: 1 2 4 5 8 9
even squares: 4 16 64Views do no work until you loop over them, and they do not copy the data.
Common mistakes#
Practice#
Practice exercise
Given std::vector<std::string> words = {"kiwi", "apple", "fig", "banana", "date", "cherry"};, use algorithms to: sort the words by length (shortest first, alphabetical for ties), count the words longer than 4 letters, and find the first word starting with 'b'.
Show solution
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> words = {"kiwi", "apple", "fig", "banana", "date", "cherry"};
std::sort(words.begin(), words.end(), [](const std::string& a, const std::string& b) {
if (a.size() != b.size()) return a.size() < b.size();
return a < b;
});
for (const auto& w : words) std::cout << w << ' ';
std::cout << '\n';
auto long_words = std::count_if(words.begin(), words.end(),
[](const std::string& w) { return w.size() > 4; });
std::cout << long_words << " words longer than 4 letters\n";
auto it = std::find_if(words.begin(), words.end(),
[](const std::string& w) { return !w.empty() && w[0] == 'b'; });
if (it != words.end()) std::cout << "first b-word: " << *it << '\n';
}fig date kiwi apple banana cherry
3 words longer than 4 letters
first b-word: bananaKey takeaway#
Finished this lesson?