C++ 标准库中的算法 (Algorithms) 是一组强大的函数模板,用于对容器或其他范围([first, last))内的元素进行搜索、排序、计数、修改等操作。自 C++20 以来,Ranges (约束算法) 的引入极大地简化了算法的使用,并增强了其通用性。C++17 则引入了执行策略,允许算法进行并行或乱序执行以提升性能。
Ranges 是 C++20 引入的一项革命性特性,它极大地简化了 STL 算法的使用,并增强了它们的组合性。
| 特性 | 优势和示例 |
| 单一 Range 参数 | 您不再需要手动传递 begin() 和 end() 迭代器。只需将整个容器(或 Range 视图)作为一个参数传递给算法即可。 |
| Projections (投影) | 简化复杂对象操作。 算法可以直接操作容器内元素的某个成员变量或计算结果,而无需使用复杂的 Lambda 表达式。例如,对一个 vector<Person> 按照 Person::age 成员进行排序。 |
| 返回类型增强 | 提供所有有用的信息。 大多数 std::ranges:: 算法不再只返回一个迭代器,而是返回一个包含所有相关结果的结构体(如 std::ranges::sort_result)。例如,ranges::copy 会返回输入范围和输出范围的结束迭代器,方便后续操作。 |
| 更强的约束 | 它们是“约束算法”,这意味着它们使用 C++20 的 Concepts 确保传入的迭代器和 Range 满足算法所需的最低要求,从而提供更清晰的编译错误。 |
示例:
std::vector<int> v{7, 1, 4, 0, -1};
// 经典算法:需要显式传入begin()和end()
std::sort(v.begin(), v.end());
// C++20 Ranges 算法:更简洁
std::ranges::sort(v);
执行策略 是 C++17 引入的功能,它允许程序员通过向算法传递一个策略对象,来指示算法如何执行——是串行、并行还是乱序执行,从而在多核 CPU 上实现性能优化。
| 策略类型 | 全局对象 | C++ 版本 | 描述 |
sequenced_policy | seq | C++17 | 序列化执行:算法按顺序执行,不会使用并行或乱序操作。这是所有算法的默认行为。 |
parallel_policy | par | C++17 | 并行执行:算法可以在不同的线程中并发执行。它保证了并发性,但不保证指令的顺序。 |
parallel_unsequenced_policy | par_unseq | C++17 | 并行且乱序执行:结合了并行和乱序执行,允许并发执行,同时允许编译器进行矢量化 (vectorization) 优化。 |
unsequenced_policy | unseq | C++20 | 乱序执行:不保证并行,但允许编译器对单个线程中的操作进行乱序处理(矢量化),以提高性能。 |
头文件: 所有执行策略都定义在 <execution> 头文件中,并位于 std::execution 命名空间下(尽管全局对象如 std::par 在 std 命名空间)。
示例:
#include <algorithm>
#include <execution>
#include <vector>
std::vector<int> data = ...;
// 使用并行策略对数据进行排序,以利用多核CPU
std::sort(std::execution::par, data.begin(), data.end());
// C++20 Ranges 版本也支持策略(如果算法有重载)
std::ranges::sort(std::execution::par, data);
在使用执行策略时,有一个关键的安全限制需要注意:
对于大多数并行算法(除了 std::for_each 和 std::for_each_n):
- 如果 Range 中的元素类型 \( T \) 满足 Trivial Copy Construction (
std::is_trivially_copy_constructible_v<T> == true) 和 Trivial Destruction (std::is_trivially_destructible_v<T> == true),库可以对元素进行任意复制,以便在不同的并行线程之间分发数据。
这意味着: 如果你的自定义对象具有非平凡(复杂)的构造函数、析构函数或资源管理,使用并行策略时需要额外小心,以确保你的操作是线程安全的。对于基本类型(如 int, float)和简单的 C 结构体,这通常不是问题。
主要头文件:
<algorithm>:包含绝大多数经典的非修改序列操作。
<ranges>:包含所有 ranges:: 版本的算法。
| 批处理操作 (Batch operations) | C++ 版本 | 头文件 | 描述 (功能) |
| for_each / ranges::for_each | (C++20) | <algorithm> / <ranges> | 对范围内的元素应用一个一元函数对象 |
| for_each_n / ranges::for_each_n | (C++17) / (C++20) | <algorithm> / <ranges> | 对序列的前 \( N \) 个元素应用一个函数对象 |
| 搜索操作 (Search operations) | C++ 版本 | 头文件 | 描述 (功能) |
| all_of / ranges::all_of | (C++11) / (C++20) | <algorithm> / <ranges> | 检查一个谓词对范围内的所有元素是否为真 |
| any_of / ranges::any_of | (C++11) / (C++20) | <algorithm> / <ranges> | 检查一个谓词对范围内的任一元素是否为真 |
| none_of / ranges::none_of | (C++11) / (C++20) | <algorithm> / <ranges> | 检查一个谓词对范围内的所有元素是否为假 |
| ranges::contains | (C++23) | <ranges> | 检查范围是否包含给定元素 |
| ranges::contains_subrange | (C++23) | <ranges> | 检查范围是否包含给定子范围 |
| find / ranges::find | (C++20) | <algorithm> / <ranges> | 查找满足特定条件的第一个元素 |
| find_if / ranges::find_if | (C++11) / (C++20) | <algorithm> / <ranges> | 查找满足谓词的第一个元素 |
| find_if_not / ranges::find_if_not | (C++11) / (C++20) | <algorithm> / <ranges> | 查找不满足谓词的第一个元素 |
| ranges::find_last | (C++23) | <ranges> | 查找满足特定条件的最后一个元素 |
| ranges::find_last_if | (C++23) | <ranges> | 查找满足谓词的最后一个元素 |
| ranges::find_last_if_not | (C++23) | <ranges> | 查找不满足谓词的最后一个元素 |
| find_end / ranges::find_end | (C++20) | <algorithm> / <ranges> | 查找某一范围内的最后一个序列 |
| find_first_of / ranges::find_first_of | (C++20) | <algorithm> / <ranges> | 搜索一组元素中的任意一个 |
| adjacent_find / ranges::adjacent_find | (C++20) | <algorithm> / <ranges> | 查找第一个两个相邻且相等的项(或满足给定谓词) |
| count / ranges::count | (C++20) | <algorithm> / <ranges> | 返回满足特定条件的元素的数量 |
| count_if / ranges::count_if | (C++20) | <algorithm> / <ranges> | 返回满足谓词的元素的数量 |
| mismatch / ranges::mismatch | (C++20) | <algorithm> / <ranges> | 查找两个范围第一次不同的位置 |
| equal / ranges::equal | (C++20) | <algorithm> / <ranges> | 确定两组元素是否相同 |
| search / ranges::search | (C++20) | <algorithm> / <ranges> | 搜索一个元素范围的第一次出现 |
| search_n / ranges::search_n | (C++20) | <algorithm> / <ranges> | 搜索一个元素在范围中连续出现 \( N \) 次的第一次出现 |
| ranges::starts_with | (C++23) | <ranges> | 检查一个范围是否以另一个范围开始 |
| ranges::ends_with | (C++23) | <ranges> | 检查一个范围是否以另一个范围结束 |
| 折叠操作 (Fold operations) | C++ 版本 | 头文件 | 描述 (功能) |
| ranges::fold_left | (C++23) | <ranges> | 对一系列元素进行左折叠 |
| ranges::fold_left_first | (C++23) | <ranges> | 使用第一个元素作为初始值对一系列元素进行左折叠 |
| ranges::fold_right | (C++23) | <ranges> | 对一系列元素进行右折叠 |
| ranges::fold_right_last | (C++23) | <ranges> | 使用最后一个元素作为初始值对一系列元素进行右折叠 |
| ranges::fold_left_with_iter | (C++23) | <ranges> | 对一系列元素进行左折叠,并返回 (迭代器, 值) 对 |
| ranges::fold_left_first_with_iter | (C++23) | <ranges> | 使用第一个元素作为初始值对一系列元素进行左折叠,并返回 (迭代器, 可选值) 对 |
主要头文件:
<algorithm>:包含绝大多数经典的修改序列操作。
<ranges>:包含所有 ranges:: 版本的算法。
<utility>:包含 std::swap 和 std::iter_swap。
| 复制操作 (Copy operations) | C++ 版本 | 头文件 | 描述 (功能) |
| copy / ranges::copy | (C++11) / (C++20) | <algorithm> / <ranges> | 将一个元素范围复制到一个新位置 |
| copy_if / ranges::copy_if | (C++11) / (C++20) | <algorithm> / <ranges> | 有条件地复制一个元素范围到新位置 |
| copy_n / ranges::copy_n | (C++11) / (C++20) | <algorithm> / <ranges> | 将指定数量的元素复制到一个新位置 |
| copy_backward / ranges::copy_backward | (C++20) | <algorithm> / <ranges> | 以向后顺序复制一个元素范围 |
| move / ranges::move | (C++11) / (C++20) | <algorithm> / <ranges> | 将一个元素范围移动到一个新位置 |
| move_backward / ranges::move_backward | (C++11) / (C++20) | <algorithm> / <ranges> | 以向后顺序移动一个元素范围 |
| 交换操作 (Swap operations) | C++ 版本 | 头文件 | 描述 (功能) |
| swap | (C++11) | <utility> | 交换两个对象的值 |
| swap_ranges / ranges::swap_ranges | (C++20) | <algorithm> / <ranges> | 交换两个元素范围 |
| iter_swap | | <utility> | 交换两个迭代器所指向的元素 |
| 变换操作 (Transformation operations) | C++ 版本 | 头文件 | 描述 (功能) |
| transform / ranges::transform | (C++20) | <algorithm> / <ranges> | 对一个元素范围应用一个函数,并将结果存储在目标范围中 |
| replace / ranges::replace | (C++20) | <algorithm> / <ranges> | 将所有满足特定条件的值替换为另一个值 |
| replace_if / ranges::replace_if | (C++20) | <algorithm> / <ranges> | 将所有满足谓词的值替换为另一个值 |
| replace_copy / ranges::replace_copy | (C++20) | <algorithm> / <ranges> | 复制一个范围,并将满足特定条件的元素替换为另一个值 |
| replace_copy_if / ranges::replace_copy_if | (C++20) | <algorithm> / <ranges> | 复制一个范围,并将满足谓词的元素替换为另一个值 |
| 生成操作 (Generation operations) | C++ 版本 | 头文件 | 描述 (功能) |
| fill / ranges::fill | (C++20) | <algorithm> / <ranges> | 将给定值赋值给范围内的每个元素 |
| fill_n / ranges::fill_n | (C++20) | <algorithm> / <ranges> | 将给定值赋值给范围内的 \( N \) 个元素 |
| generate / ranges::generate | (C++20) | <algorithm> / <ranges> | 将连续函数调用的结果赋值给范围内的每个元素 |
| generate_n / ranges::generate_n | (C++20) | <algorithm> / <ranges> | 将连续 \( N \) 次函数调用的结果赋值给范围内的 \( N \) 个元素 |
这里的“移除”通常是逻辑移除,通过将未被移除的元素移动到范围的前部来实现,并返回新的逻辑尾部。
| 移除操作 (Removing operations) | C++ 版本 | 头文件 | 描述 (功能) |
| remove / ranges::remove | (C++20) | <algorithm> / <ranges> | 移除满足特定条件的元素(逻辑移除) |
| remove_if / ranges::remove_if | (C++20) | <algorithm> / <ranges> | 移除满足谓词的元素(逻辑移除) |
| remove_copy / ranges::remove_copy | (C++20) | <algorithm> / <ranges> | 复制一个范围,省略满足特定条件的元素 |
| remove_copy_if / ranges::remove_copy_if | (C++20) | <algorithm> / <ranges> | 复制一个范围,省略满足谓词的元素 |
| unique / ranges::unique | (C++20) | <algorithm> / <ranges> | 移除范围内的连续重复元素(逻辑移除) |
| unique_copy / ranges::unique_copy | (C++20) | <algorithm> / <ranges> | 创建一个不含连续重复元素的范围副本 |
| 顺序改变操作 (Order-changing operations) | C++ 版本 | 头文件 | 描述 (功能) |
| reverse / ranges::reverse | (C++20) | <algorithm> / <ranges> | 反转范围内的元素顺序 |
| reverse_copy / ranges::reverse_copy | (C++20) | <algorithm> / <ranges> | 创建一个反转后的范围副本 |
| rotate / ranges::rotate | (C++20) | <algorithm> / <ranges> | 旋转范围内的元素顺序 |
| rotate_copy / ranges::rotate_copy | (C++20) | <algorithm> / <ranges> | 复制并旋转一个元素范围 |
| shift_left / ranges::shift_left | (C++20) / (C++23) | <algorithm> / <ranges> | 左移范围内的元素 |
| shift_right / ranges::shift_right | (C++20) / (C++23) | <algorithm> / <ranges> | 右移范围内的元素 |
| shuffle / ranges::shuffle | (C++11) / (C++20) | <algorithm> / <ranges> | 随机重新排序范围内的元素 |
| 采样操作 (Sampling operations) | C++ 版本 | 头文件 | 描述 (功能) |
| sample / ranges::sample | (C++17) / (C++20) | <algorithm> / <ranges> | 从序列中选择 \( N \) 个随机元素 |
主要头文件:
<algorithm>:包含绝大多数经典的排序及相关操作。
<ranges>:包含所有 ranges:: 版本的算法。
| 分区操作 (Partitioning operations) | C++ 版本 | 头文件 | 描述 (功能) |
| is_partitioned / ranges::is_partitioned | (C++11) / (C++20) | <algorithm> / <ranges> | 确定范围是否被给定谓词分区 |
| partition / ranges::partition | (C++20) | <algorithm> / <ranges> | 将一个元素范围划分为两组 |
| partition_copy / ranges::partition_copy | (C++11) / (C++20) | <algorithm> / <ranges> | 复制一个范围,将元素划分为两组 |
| stable_partition / ranges::stable_partition | (C++20) | <algorithm> / <ranges> | 将元素划分为两组,同时保持它们的相对顺序 |
| partition_point / ranges::partition_point | (C++11) / (C++20) | <algorithm> / <ranges> | 定位一个已分区范围的分区点 |
| 排序操作 (Sorting operations) | C++ 版本 | 头文件 | 描述 (功能) |
| sort / ranges::sort | (C++20) | <algorithm> / <ranges> | 将一个范围排序为升序 |
| stable_sort / ranges::stable_sort | (C++20) | <algorithm> / <ranges> | 排序一个元素范围,同时保持相等元素间的相对顺序 |
| partial_sort / ranges::partial_sort | (C++20) | <algorithm> / <ranges> | 排序一个范围的前 \( N \) 个元素 |
| partial_sort_copy / ranges::partial_sort_copy | (C++20) | <algorithm> / <ranges> | 复制并部分排序一个元素范围 |
| is_sorted / ranges::is_sorted | (C++11) / (C++20) | <algorithm> / <ranges> | 检查一个范围是否已排序为升序 |
| is_sorted_until / ranges::is_sorted_until | (C++11) / (C++20) | <algorithm> / <ranges> | 查找最大的已排序子范围 |
| nth_element / ranges::nth_element | (C++20) | <algorithm> / <ranges> | 部分排序给定范围,确保它被给定元素分区 |
这些操作要求输入范围必须是已排序的。
| 二分搜索操作 (Binary search operations) | C++ 版本 | 头文件 | 描述 (功能) |
| lower_bound / ranges::lower_bound | (C++20) | <algorithm> / <ranges> | 返回第一个不小于给定值的元素的迭代器 |
| upper_bound / ranges::upper_bound | (C++20) | <algorithm> / <ranges> | 返回第一个大于给定值的元素的迭代器 |
| equal_range / ranges::equal_range | (C++20) | <algorithm> / <ranges> | 返回匹配特定键的元素的范围 |
| binary_search / ranges::binary_search | (C++20) | <algorithm> / <ranges> | 确定一个元素是否存在于一个部分有序的范围中 |
这些操作要求输入范围必须是已排序的。
| 集合操作 (Set operations) | C++ 版本 | 头文件 | 描述 (功能) |
| includes / ranges::includes | (C++20) | <algorithm> / <ranges> | 如果一个序列是另一个序列的子序列则返回 true |
| set_union / ranges::set_union | (C++20) | <algorithm> / <ranges> | 计算两个集合的并集 |
| set_intersection / ranges::set_intersection | (C++20) | <algorithm> / <ranges> | 计算两个集合的交集 |
| set_difference / ranges::set_difference | (C++20) | <algorithm> / <ranges> | 计算两个集合的差集 |
| set_symmetric_difference / ranges::set_symmetric_difference | (C++20) | <algorithm> / <ranges> | 计算两个集合的对称差集 |
| 合并操作 (Merge operations) | C++ 版本 | 头文件 | 描述 (功能) |
| merge / ranges::merge | (C++20) | <algorithm> / <ranges> | 合并两个已排序的范围 |
| inplace_merge / ranges::inplace_merge | (C++20) | <algorithm> / <ranges> | 在原地合并两个有序范围 |
这些操作用于维护最大堆 (max heap) 的属性。
| 堆操作 (Heap operations) | C++ 版本 | 头文件 | 描述 (功能) |
| push_heap / ranges::push_heap | (C++20) | <algorithm> / <ranges> | 向最大堆中添加一个元素 |
| pop_heap / ranges::pop_heap | (C++20) | <algorithm> / <ranges> | 从最大堆中移除最大的元素 |
| make_heap / ranges::make_heap | (C++20) | <algorithm> / <ranges> | 将一个元素范围创建为最大堆 |
| sort_heap / ranges::sort_heap | (C++20) | <algorithm> / <ranges> | 将一个最大堆转换为一个升序排序的元素范围 |
| is_heap / ranges::is_heap | (C++11) / (C++20) | <algorithm> / <ranges> | 检查给定范围是否为最大堆 |
| is_heap_until / ranges::is_heap_until | (C++11) / (C++20) | <algorithm> / <ranges> | 查找作为最大堆的最大子范围 |
| 最小/最大操作 (Minimum/maximum operations) | C++ 版本 | 头文件 | 描述 (功能) |
| max / ranges::max | (C++20) | <algorithm> / <ranges> | 返回给定值中的较大者 |
| max_element / ranges::max_element | (C++20) | <algorithm> / <ranges> | 返回范围中的最大元素 |
| min / ranges::min | (C++20) | <algorithm> / <ranges> | 返回给定值中的较小者 |
| min_element / ranges::min_element | (C++20) | <algorithm> / <ranges> | 返回范围中的最小元素 |
| minmax / ranges::minmax | (C++11) / (C++20) | <algorithm> / <ranges> | 返回两个元素中的较小者和较大者 |
| minmax_element / ranges::minmax_element | (C++11) / (C++20) | <algorithm> / <ranges> | 返回范围中的最小和最大元素 |
| clamp / ranges::clamp | (C++17) / (C++20) | <algorithm> / <ranges> | 将一个值钳制在一对边界值之间 |
| 字典序比较操作 (Lexicographical comparison operations) | C++ 版本 | 头文件 | 描述 (功能) |
| lexicographical_compare / ranges::lexicographical_compare | (C++20) | <algorithm> / <ranges> | 如果一个范围字典序上小于另一个,则返回 true |
| lexicographical_compare_three_way | (C++20) | <algorithm> | 使用三路比较比较两个范围 |
| 排列操作 (Permutation operations) | C++ 版本 | 头文件 | 描述 (功能) |
| next_permutation / ranges::next_permutation | (C++20) | <algorithm> / <ranges> | 生成范围元素的下一个更大的字典序排列 |
| prev_permutation / ranges::prev_permutation | (C++20) | <algorithm> / <ranges> | 生成范围元素的下一个更小的字典序排列 |
| is_permutation / ranges::is_permutation | (C++11) / (C++20) | <algorithm> / <ranges> | 确定一个序列是否是另一个序列的排列 |
主要头文件:
<numeric>:包含所有传统的数值算法和 C++17 的并行数值算法。
<ranges>:包含 ranges::iota。
| 数值操作 (Numeric operations) | C++ 版本 | 头文件 | 描述 (功能) |
| iota / ranges::iota | (C++11) / (C++23) | <numeric> / <ranges> | 用递增的起始值填充一个范围 |
| accumulate | | <numeric> | 对一个元素范围求和或折叠 |
| inner_product | | <numeric> | 计算两个元素范围的内积 |
| adjacent_difference | | <numeric> | 计算一个范围中相邻元素之间的差值 |
| partial_sum | | <numeric> | 计算一个元素范围的部分和 |
| reduce | (C++17) | <numeric> | 类似于 std::accumulate,但无序 |
| exclusive_scan | (C++17) | <numeric> | 类似于 std::partial_sum,但不包括第 \( N \) 个输入元素在第 \( N \) 个和中 |
| inclusive_scan | (C++17) | <numeric> | 类似于 std::partial_sum,包括第 \( N \) 个输入元素在第 \( N \) 个和中 |
| transform_reduce | (C++17) | <numeric> | 应用一个可调用对象,然后无序归约 |
| transform_exclusive_scan | (C++17) | <numeric> | 应用一个可调用对象,然后计算独占扫描 |
| transform_inclusive_scan | (C++17) | <numeric> | 应用一个可调用对象,然后计算包含扫描 |
主要头文件:
| 未初始化内存操作 (Operations on uninitialized memory) | C++ 版本 | 头文件 | 描述 (功能) |
| uninitialized_copy / ranges::uninitialized_copy | (C++20) | <memory> | 将一系列对象复制到一块未初始化内存区域 |
| uninitialized_copy_n / ranges::uninitialized_copy_n | (C++11) / (C++20) | <memory> | 将指定数量的对象复制到一块未初始化内存区域 |
| uninitialized_fill / ranges::uninitialized_fill | (C++20) | <memory> | 将一个对象复制赋值给一块未初始化内存区域 |
| uninitialized_fill_n / ranges::uninitialized_fill_n | (C++20) | <memory> | 将一个对象复制赋值给指定数量的未初始化内存区域 |
| uninitialized_move / ranges::uninitialized_move | (C++17) / (C++20) | <memory> | 将一系列对象移动到一块未初始化内存区域 |
| uninitialized_move_n / ranges::uninitialized_move_n | (C++17) / (C++20) | <memory> | 将指定数量的对象移动到一块未初始化内存区域 |
| uninitialized_default_construct / ranges::uninitialized_default_construct | (C++17) / (C++20) | <memory> | 在一块未初始化内存区域中默认构造对象 |
| uninitialized_default_construct_n / ranges::uninitialized_default_construct_n | (C++17) / (C++20) | <memory> | 在一块未初始化内存区域中默认构造 \( N \) 个对象 |
| uninitialized_value_construct / ranges::uninitialized_value_construct | (C++17) / (C++20) | <memory> | 在一块未初始化内存区域中值构造对象 |
| uninitialized_value_construct_n / ranges::uninitialized_value_construct_n | (C++17) / (C++20) | <memory> | 在一块未初始化内存区域中值构造 \( N \) 个对象 |
| destroy / ranges::destroy | (C++17) / (C++20) | <memory> | 销毁一系列对象 |
| destroy_n / ranges::destroy_n | (C++17) / (C++20) | <memory> | 销毁范围内的 \( N \) 个对象 |
| destroy_at / ranges::destroy_at | (C++17) / (C++20) | <memory> | 销毁给定地址处的对象 |
| construct_at / ranges::construct_at | (C++20) | <memory> | 在给定地址处创建一个对象 |
主要头文件:
| 随机数生成 (Random number generation) | C++ 版本 | 头文件 | 描述 (功能) |
| ranges::generate_random | (C++26) | <ranges> | 用均匀随机位生成器填充一个随机数范围 |
主要头文件:
| C 库函数 (C library functions) | C++ 版本 | 头文件 | 描述 (功能) |
| qsort | | <cstdlib> | 排序一个类型未指定的元素范围 |
| bsearch | | <cstdlib> | 搜索一个类型未指定的数组中的元素 |
主要头文件:
| 执行策略类型 (Execution policy types) | 宏/类/对象 | C++ 版本 | 头文件 | 描述 (功能) |
sequenced_policy (seq) | 类 / 全局对象 | (C++17) | <execution> | 序列化执行(无并行) |
parallel_policy (par) | 类 / 全局对象 | (C++17) | <execution> | 并行执行 |
parallel_unsequenced_policy (par\_unseq) | 类 / 全局对象 | (C++17) | <execution> | 并行且乱序执行 |
unsequenced_policy (unseq) | 类 / 全局对象 | (C++20) | <execution> | 乱序执行(允许编译器向量化) |
| is_execution_policy | 类模板 | (C++17) | <execution> | 测试一个类是否表示一个执行策略 |