C++ STL算法总结
C++ 标准库的 <algorithm>
提供了大量通用的算法, 用于操作容器, 范围和迭代器. 这些算法可以归纳为几大类, 涵盖排序, 搜索, 修改, 统计等功能.
以下是 <algorithm>
中算法的分类和常用方法的总结:
批处理操作
for_each
,ranges::for_each
: 对范围内的每一个元素执行操作for_each_n
,ranges::for_each_n
(C++17): 对一个序列的前 N 个元素执行操作
样例代码
// for_each
std::for_each(v.begin(), v.end(), [](int& n) { n *= 2; });
fmt::println("{}", v); // [2, 4, 6, 8, 10]
// ranges::for_each (C++20)
std::ranges::for_each(v, [](int& n) { n = 1; });
fmt::println("{}", v); // [1, 1, 1, 1, 1]
// for_each_n (C++17)
std::for_each_n(v.begin(), 3, [](int& n) { n = 2; });
fmt::println("{}", v); // [2, 2, 2, 1, 1]
// ranges::for_each_n (C++20)
std::ranges::for_each_n(v.begin(), 2, [](int& n) { n = 3; });
fmt::println("{}", v); // [3, 3, 2, 1, 1]
搜索操作
这些算法不会修改容器中的元素,主要用于查询、统计和范围操作。
检查元素
all_of
,ranges::all_of
(C++20): 检查范围内所有元素是否满足条件。any_of
,ranges::any_of
(C++20): 检查范围内是否存在满足条件的元素。none_of
,ranges::none_of
(C++20): 检查范围内所有元素是否都不满足条件。
std::vector<int> v = {1, 2, 3, 4, 5};
// all_of
fmt::println("All elements greater than 0: {}",
std::all_of(v.begin(), v.end(), [](int n) { return n > 0; }));
// ranges::all_of (C++20)
fmt::println("All elements greater than 1: {}",
std::ranges::all_of(v, [](int n) { return n > 1; }));
// any_of
fmt::println("Any element greater than 4: {}",
std::any_of(v.begin(), v.end(), [](int n) { return n > 4; }));
// ranges::any_of (C++20)
fmt::println("Any element greater than 6: {}",
std::ranges::any_of(v, [](int n) { return n > 6; }));
// none_of
fmt::println("None of the elements greater than 6: {}",
std::none_of(v.begin(), v.end(), [](int n) { return n > 6; }));
// ranges::none_of (C++20)
fmt::println("None of the elements greater than 2: {}",
std::ranges::none_of(v, [](int n) { return n > 2; }));
查找
-
ranges::contains
(C++23): 检查范围是否包含指定值。 -
ranges::contains_subrange
(C++23): 检查范围是否包含指定子范围。 -
find
,ranges::find
: 查找第一个等于指定值的元素。 -
find_if
,ranges::find_if
: 查找第一个满足条件的元素。 -
find_if_not
,ranges::find_if_not
: 查找第一个不满足条件的元素。 -
ranges::find_last
(C++23):查找最后一个等于指定值的元素。 -
ranges::find_last_if
(C++23): 查找最后一个满足条件的元素。 -
ranges::find_last_if_not
(C++23): 查找最后一个不满足条件的元素。 -
find_end
,ranges::find_end
: 查找某个子范围在另一个范围中最后一次出现的位置。 -
find_first_of
,ranges::find_first_of
: 查找两个范围中第一个匹配的元素。 -
adjacent_find
,ranges::adjacent_find
: 查找范围内相邻且相等的元素。
std::vector<int> v = {1, 2, 3, 4, 5, 3};
std::vector<int> sub_v = {3, 4};
// ranges::contains (C++23)
fmt::print("Vector contains 3: {}\n", std::ranges::contains(v, 3));
// Vector contains 3: true
// ranges::contains_subrange (C++23)
fmt::print("Vector contains sub - range {{3, 4}}: {}\n",
std::ranges::contains_subrange(v, sub_v));
// Vector contains sub - range {3, 4}: true
// find
if (auto it = std::find(v.begin(), v.end(), 3); it != v.end()) {
fmt::print("Found 3 at position: {}\n", std::distance(v.begin(), it));
// Found 3 at position: 2
}
// ranges::find
if (auto rit = std::ranges::find(v, 3); rit != v.end()) {
fmt::print("Found 3 at position (ranges): {}\n",
std::distance(v.begin(), rit));
// Found 3 at position (ranges): 2
}
// find_if
// 查找第一个大于 3 的元素,第一个大于 3 的元素是 4,其位置索引是 3
if (auto it_if =
std::find_if(v.begin(), v.end(), [](int n) { return n > 3; });
it_if != v.end()) {
fmt::print("Found element greater than 3 at position: {}\n",
std::distance(v.begin(), it_if));
// Found element greater than 3 at position: 3
}
// ranges::find_if
// 使用 ranges 版本查找第一个大于 3 的元素,结果位置索引同样是 3
if (auto rit_if = std::ranges::find_if(v, [](int n) { return n > 3; });
rit_if != v.end()) {
fmt::print("Found element greater than 3 at position (ranges): {}\n",
std::distance(v.begin(), rit_if));
// Found element greater than 3 at position (ranges): 3
}
// find_if_not
// 查找第一个不大于 3 的元素,也就是第一个小于等于 3 的元素,是 1,位置索引是0
if (auto it_if_not =
std::find_if_not(v.begin(), v.end(), [](int n) { return n > 3; });
it_if_not != v.end()) {
fmt::print("Found element not greater than 3 at position: {}\n",
std::distance(v.begin(), it_if_not));
// Found element not greater than 3 at position: 0
}
// ranges::find_if_not
// 使用 ranges 版本查找第一个不大于 3 的元素,结果位置索引还是 0
if (auto rit_if_not =
std::ranges::find_if_not(v, [](int n) { return n > 3; });
rit_if_not != v.end()) {
fmt::print("Found element not greater than 3 at position (ranges): {}\n",
std::distance(v.begin(), rit_if_not));
// Found element not greater than 3 at position (ranges): 0
}
// adjacent_find
// 查找相邻且相等的元素,向量中没有相邻且相等的元素,所以此条件不满足,不会有输出
if (auto it_adj = std::adjacent_find(v.begin(), v.end()); it_adj != v.end()) {
fmt::print("Found adjacent equal elements at position: {}\n",
std::distance(v.begin(), it_adj));
}
// ranges::adjacent_find
// 使用 ranges 版本查找相邻且相等的元素,同样不会有输出
if (auto rit_adj = std::ranges::adjacent_find(v); rit_adj != v.end()) {
fmt::print("Found adjacent equal elements at position (ranges): {}\n",
std::distance(v.begin(), rit_adj));
}
计数
count
,ranges::count
: 统计等于指定值的元素个数。count_if
,ranges::count_if
: 统计满足条件的元素个数。
std::vector<int> v = {1, 2, 3, 3, 4, 5};
// count
fmt::print("Count of 3: {}\n", std::count(v.begin(), v.end(), 3));
// Count of 3: 2
// ranges::count
fmt::print("Count of 3 (ranges): {}\n", std::ranges::count(v, 3));
// Count of 3 (ranges): 2
// count_if
fmt::print("Count of elements greater than 3: {}\n",
std::count_if(v.begin(), v.end(), [](int n) { return n > 3; }));
// Count of elements greater than 3: 2
// ranges::count_if
fmt::print("Count of elements greater than 3 (ranges): {}\n",
std::ranges::count_if(v, [](int n) { return n > 3; }));
// Count of elements greater than 3 (ranges): 2
比较
mismatch
,ranges::mismatch
: 找到两个范围中第一个不匹配的元素。equal
,ranges::equal
: 比较两个范围是否相等。search
,ranges::search
: 在一个范围中查找另一个范围第一次出现的位置。search_n
,ranges::search_n
: 在一个范围中查找连续 n 个等于指定值的元素。ranges::starts_with
: 检查一个范围是否以另一个范围开头。ranges::ends_with
: 检查一个范围是否以另一个范围结尾。
Fold operations (C++23)
ranges::fold_left
(C++23): 从左到右折叠范围中的元素。ranges::fold_left_first
(C++23): 从左到右折叠范围中的元素,初始值为范围的第一个元素。ranges::fold_right
(C++23): 从右到左折叠范围中的元素。ranges::fold_right_last
(C++23): 从右到左折叠范围中的元素,初始值为范围的最后一个元素。ranges::fold_left_with_iter
(C++23): 从左到右折叠范围中的元素,并返回迭代器。ranges::fold_left_first_with_iter
(C++23): 从左到右折叠范围中的元素,初始值为范围的第一个元素,并返回迭代器。
修改序列
这些算法会修改容器或范围中的元素.
拷贝和移动
copy
,ranges::copy
: 将一个范围的元素拷贝到另一个范围。copy_if
,ranges::copy_if
: 拷贝满足条件的元素。copy_n
,ranges::copy_n
: 拷贝指定个数的元素。copy_backward
,ranges::copy_backward
: 从后往前拷贝元素。move
,ranges::move
: 将元素从一个范围移动到另一个范围。move_backward
,ranges::move_backward
: 从后往前移动元素。
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(5);
// copy
std::copy(src.begin(), src.end(), dst.begin());
fmt::println("After std::copy: {}", dst);
// output: After std::copy: [1, 2, 3, 4, 5]
// ranges::copy
std::ranges::copy(src, dst.begin());
fmt::println("After std::ranges::copy: {}", dst);
// output: After std::ranges::copy: [1, 2, 3, 4, 5]
// copy_if
dst.clear();
dst.resize(src.size());
auto it = std::copy_if(src.begin(), src.end(), dst.begin(),
[](int num) { return num % 2 == 0; });
dst.erase(it, dst.end());
fmt::println("After std::copy_if (even numbers): {}", dst);
// output: After std::copy_if (even numbers): [2, 4]
// ranges::copy_if
dst.clear();
dst.resize(src.size());
auto result = std::ranges::copy_if(src, dst.begin(),
[](int num) { return num % 2 == 0; });
dst.erase(result.out, dst.end());
fmt::println("After std::ranges::copy_if (even numbers): {}", dst);
// output: After std::ranges::copy_if (even numbers): [2, 4]
// copy_n
dst.clear();
dst.resize(3);
std::copy_n(src.begin(), 3, dst.begin());
fmt::println("After std::copy_n (first 3 elements): {}", dst);
// output: After std::copy_n (first 3 elements): [1, 2, 3]
// ranges::copy_n
dst.clear();
dst.resize(3);
std::ranges::copy_n(src.begin(), 3, dst.begin());
fmt::println("After std::ranges::copy_n (first 3 elements): {}", dst);
// output: After std::ranges::copy_n (first 3 elements): [1, 2, 3]
// copy_backward
dst.clear();
dst.resize(src.size());
std::copy_backward(src.begin(), src.end(), dst.end());
fmt::println("After std::copy_backward: {}", dst);
// output: After std::copy_backward: [1, 2, 3, 4, 5]
// ranges::copy_backward
dst.clear();
dst.resize(src.size());
std::ranges::copy_backward(src, dst.end());
fmt::println("After std::ranges::copy_backward: {}", dst);
// output: After std::ranges::copy_backward: [1, 2, 3, 4, 5]
// move
std::vector<int> move_dst(5);
std::move(src.begin(), src.end(), move_dst.begin());
fmt::println("After std::move: {}", move_dst);
// output: After std::move: [1, 2, 3, 4, 5]
// ranges::move
std::vector<int> ranges_move_dst(5);
std::ranges::move(src, ranges_move_dst.begin());
fmt::println("After std::ranges::move: {}", ranges_move_dst);
// output: After std::ranges::move: [1, 2, 3, 4, 5]
// move_backward
std::vector<int> move_backward_dst(5);
std::move_backward(src.begin(), src.end(), move_backward_dst.end());
fmt::println("After std::move_backward: {}", move_backward_dst);
// output: After std::move_backward: [1, 2, 3, 4, 5]
// ranges::move_backward
std::vector<int> ranges_move_backward_dst(5);
std::ranges::move_backward(src, ranges_move_backward_dst.end());
fmt::println("After std::ranges::move_backward: {}",
// output: After std::ranges::move_backward: [1, 2, 3, 4, 5]
ranges_move_backward_dst);
交换操作
swap
: 交换两个值。swap_ranges
,ranges::swap_ranges
: 交换两个范围的元素。iter_swap
: 交换两个迭代器所指向的元素。
// swap
int a = 10;
int b = 20;
fmt::println("Before std::swap: a = {}, b = {}", a,
b); // 预期输出:Before std::swap: a = 10, b = 20
std::swap(a, b);
fmt::println("After std::swap: a = {}, b = {}", a,
b); // 预期输出:After std::swap: a = 20, b = 10
// swap_ranges 和 ranges::swap_ranges
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = {6, 7, 8, 9, 10};
fmt::println("Before std::swap_ranges:");
fmt::println("vec1 = {}", vec1); // 预期输出:vec1 = [1, 2, 3, 4, 5]
fmt::println("vec2 = {}", vec2); // 预期输出:vec2 = [6, 7, 8, 9, 10]
std::swap_ranges(vec1.begin(), vec1.end(), vec2.begin());
fmt::println("After std::swap_ranges:");
fmt::println("vec1 = {}", vec1); // 预期输出:vec1 = [6, 7, 8, 9, 10]
fmt::println("vec2 = {}", vec2); // 预期输出:vec2 = [1, 2, 3, 4, 5]
// 恢复 vec1 和 vec2 以便测试 ranges::swap_ranges
vec1 = {1, 2, 3, 4, 5};
vec2 = {6, 7, 8, 9, 10};
fmt::println("Before std::ranges::swap_ranges:");
fmt::println("vec1 = {}", vec1); // 预期输出:vec1 = [1, 2, 3, 4, 5]
fmt::println("vec2 = {}", vec2); // 预期输出:vec2 = [6, 7, 8, 9, 10]
std::ranges::swap_ranges(vec1, vec2);
fmt::println("After std::ranges::swap_ranges:");
fmt::println("vec1 = {}", vec1); // 预期输出:vec1 = [6, 7, 8, 9, 10]
fmt::println("vec2 = {}", vec2); // 预期输出:vec2 = [1, 2, 3, 4, 5]
// iter_swap
std::vector<int> vec3 = {100, 200};
fmt::println("Before std::iter_swap: vec3 = {}",
vec3); // 预期输出:Before std::iter_swap: vec3 = [100, 200]
std::iter_swap(vec3.begin(), std::next(vec3.begin()));
fmt::println("After std::iter_swap: vec3 = {}",
vec3); // 预期输出:After std::iter_swap: vec3 = [200, 100]
变换操作
变换
transform
,ranges::transform
: 对范围内的每个元素应用函数,并将结果存储到另一个范围。
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::vector<int> result(numbers.size());
// 使用 transform 将每个元素乘以 2 并存储到 result 中
std::transform(numbers.begin(), numbers.end(), result.begin(),
[](int num) { return num * 2; });
// 使用 ranges::transform 做同样的操作
std::vector<int> resultRanges(numbers.size());
std::ranges::transform(numbers, resultRanges.begin(),
[](int num) { return num * 2; });
// 输出 transform 的结果
fmt::print("transform 结果: {}\n", result);
// 输出 ranges::transform 的结果
fmt::print("ranges::transform 结果: {}\n", resultRanges);
替换
replace
,ranges::replace
: 将范围内的指定值替换为新值。replace_if
,ranges::replace_if
: 替换满足条件的元素。replace_copy
,ranges::replace_copy
: 拷贝范围中的元素,同时将指定值替换为新值。replace_copy_if
,ranges::replace_copy_if
: 拷贝范围中的元素,同时将满足条件的元素替换为新值。
生成操作
fill
,ranges::fill
: 将范围内所有元素赋值为指定值。fill_n
,ranges::fill_n
: 对指定个数的元素赋值。generate
,ranges::generate
: 使用函数生成范围内的值。generate_n
,ranges::generate_n
: 为前 N 个元素生成值。
移除操作
remove
,ranges::remove
: 移除指定值的元素(逻辑移除,不改变容器大小)。remove_if
,ranges::remove_if
: 移除满足条件的元素(逻辑移除,不改变容器大小)。remove_copy
,ranges::remove_copy
: 拷贝范围中的元素,同时移除指定值的元素。remove_copy_if
,ranges::remove_copy_if
: 拷贝范围中的元素,同时移除满足条件的元素。unique
,ranges::unique
: 移除相邻的重复元素(逻辑移除,不改变容器大小)。unique_copy
,ranges::unique_copy
: 拷贝范围中的元素,同时移除相邻的重复元素。
改变顺序的操作
reverse
,ranges::reverse
: 反转范围内的元素顺序。reverse_copy
,ranges::reverse_copy
: 反转范围内的元素顺序并拷贝到另一个范围。rotate
,ranges::rotate
: 旋转范围内的元素。rotate_copy
,ranges::rotate_copy
: 旋转范围内的元素并拷贝到另一个范围。shift_left
,ranges::shift_left
: 向左移动范围内的元素。shift_right
,ranges::shift_right
: 向右移动范围内的元素。shuffle
,ranges::shuffle
: 随机打乱范围内的元素。random_shuffle
: 随机打乱范围内的元素(C++14 前)。
抽样操作
sample
,ranges::sample
: 从范围中随机抽样。
partition 操作
is_partitioned
,ranges::is_partitioned
: 检查范围是否已被分区。partition
,ranges::partition
: 将范围中的元素按照条件分区。partition_copy
,ranges::partition_copy
: 将范围中的元素按照条件分区并拷贝到两个不同的范围。stable_partition
,ranges::stable_partition
: 将范围中的元素按照条件分区,同时保持相对顺序。partition_point
,ranges::partition_point
: 查找分区点。
排序相关算法
排序算法对范围中的元素重新排列.
sort
,ranges::sort
: 对范围内的元素进行升序排序。stable_sort
,ranges::stable_sort
: 稳定排序,保持相等元素的顺序。partial_sort
,ranges::partial_sort
: 对范围的前几个元素进行排序。partial_sort_copy
,ranges::partial_sort_copy
: 部分排序并拷贝。is_sorted
,ranges::is_sorted
: 检查范围是否已排序。is_sorted_until
,ranges::is_sorted_until
: 查找范围中第一个未排序的元素。nth_element
,ranges::nth_element
: 将指定位置的元素调整到排序后的位置。
二分查找
lower_bound
,ranges::lower_bound
: 找到第一个不小于指定值的位置。upper_bound
,ranges::upper_bound
: 找到第一个大于指定值的位置。equal_range
,ranges::equal_range
: 找到等于指定值的范围。binary_search
,ranges::binary_search
: 检查范围内是否包含指定值(范围必须有序)。
集合操作
includes
,ranges::includes
: 检查一个范围是否包含另一个范围。set_union
,ranges::set_union
: 计算两个有序范围的并集。set_intersection
,ranges::set_intersection
: 计算两个有序范围的交集。set_difference
,ranges::set_difference
: 计算两个有序范围的差集。set_symmetric_difference
,ranges::set_symmetric_difference
: 计算两个有序范围的对称差集。
Merge operations
merge
,ranges::merge
: 合并两个有序范围。inplace_merge
,ranges::inplace_merge
: 原地合并两个有序范围。
堆操作
push_heap
,ranges::push_heap
: 将新元素插入堆。pop_heap
,ranges::pop_heap
: 从堆中移除最大元素。make_heap
,ranges::make_heap
: 将范围转换为堆。sort_heap
,ranges::sort_heap
: 对堆排序。is_heap
,ranges::is_heap
: 检查范围是否为堆。is_heap_until
,ranges::is_heap_until
: 查找范围中第一个不满足堆性质的元素。
最大最小值
max
,ranges::max
: 返回两个值中的最大值。max_element
,ranges::max_element
: 查找范围内的最大元素。min
,ranges::min
: 返回两个值中的最小值。min_element
,ranges::min_element
: 查找范围内的最小元素。minmax
,ranges::minmax
: 返回两个值中的最小值和最大值。minmax_element
,ranges::minmax_element
: 查找范围内的最小元素和最大元素。clamp
,ranges::clamp
: 将值限制在指定范围内。
Lexicographical comparison operations
lexicographical_compare
,ranges::lexicographical_compare
: 按字典序比较两个范围。lexicographical_compare_three_way
: 按字典序比较两个范围(三路比较)。
排列
next_permutation
,ranges::next_permutation
: 生成下一个字典序排列。prev_permutation
,ranges::prev_permutation
: 生成上一个字典序排列。is_permutation
,ranges::is_permutation
: 检查两个范围是否为同一排列。
数值操作
iota
,ranges::iota
: 生成递增序列。accumulate
: 计算范围内所有元素的累积和。inner_product
: 计算两个范围的内积。adjacent_difference
: 计算范围中相邻元素的差。partial_sum
: 计算范围的部分和。reduce
(C++17): 并行计算范围内元素的累积和。inclusive_scan
: 计算范围的前缀和(包含当前元素)。exclusive_scan
: 计算范围的前缀和(不包含当前元素)。transform_reduce
: 并行计算范围内元素的累积和,同时应用变换函数。transform_inclusive_scan
: 计算范围的前缀和(包含当前元素),同时应用变换函数。transform_exclusive_scan
: 计算范围的前缀和(不包含当前元素),同时应用变换函数。