C++ 标准库算法全景指南

C++ 标准库 <algorithm> 和 <numeric> 提供了 100+ 个算法,配合迭代器和范围(C++20),覆盖了绝大多数数据处理需求。本文按功能分类系统梳理,附带典型用法与复杂度。


1. 非修改序列操作

只读遍历,不改变元素值。

算法 作用 复杂度 典型场景
all_of / any_of / none_of 全真/任真/全假判断 O(n) 校验容器是否满足条件
for_each 对每个元素执行操作 O(n) 仅有副作用的遍历(C++20 推荐 ranges::for_each)
find / find_if / find_if_not 查找首个匹配元素 O(n) 线性查找
find_end 查找子序列最后一次出现 O(n·m) 子串/子序列搜索
find_first_of 查找集合中任一元素首次出现 O(n·m) 多模式首次匹配
adjacent_find 查找相邻重复元素 O(n) 去重前检测
count / count_if 统计匹配元素个数 O(n) 频次统计
mismatch 找到两序列首个不匹配位置 O(min(n,m)) 差异对比
equal 判断两序列逐元素相等 O(n) 容器相等性检查
is_permutation 判断是否为排列关系 O(n²) 平均 O(n) 乱序相等性
search / search_n 子序列/连续 n 次值查找 O(n·m) 模式匹配

C++20 所有算法在 std::ranges 命名空间有对应版本,支持投影与范围直接传参,如 ranges::find(v, 42)。


2. 修改序列操作

改变元素值或位置。

算法 作用 复杂度 备注
copy / copy_if / copy_n / copy_backward 拷贝元素 O(n) 目标空间需预留
move / move_backward 移动元素 O(n) C++11,利用移动语义
fill / fill_n 赋固定值 O(n) 初始化/重置
transform 一元/二元映射 O(n) out = op(in) 或 op(in1, in2)
generate / generate_n 用生成器填充 O(n) 随机数、序列生成
remove / remove_if / remove_copy / remove_copy_if 移除满足条件元素 O(n) 不改变容器大小 ,返回新逻辑末尾,需配合 erase
replace / replace_if / replace_copy / replace_copy_if 替换满足条件元素 O(n) 就地或拷贝替换
swap / swap_ranges / iter_swap 交换元素/范围 O(1)/O(n) 交换两对象或两范围对应位置
reverse / reverse_copy 反转序列 O(n) 双向迭代器
rotate / rotate_copy 左旋(首元素移至中间) O(n) 循环移位
shuffle 随机打乱 O(n) 需 UniformRandomBitGenerator
unique / unique_copy 移除相邻重复 O(n) 需先排序才能全局去重
partition / stable_partition / partition_copy 按谓词分区 O(n) / O(n log n) stable_ 保持相对序
is_partitioned 判断是否已分区 O(n) 配合 partition_point 定位分界

3. 排序与相关操作

算法 作用 复杂度 稳定性 适用场景
sort 全排序 O(n log n) ❌ 通用排序
stable_sort 稳定全排序 O(n log n) / O(n log² n) ✅ 需保持等值相对序
partial_sort 前 k 小排序 O(n log k) ❌ Top-K
partial_sort_copy 拷贝并部分排序 O(n log k) ❌ 只需前 k 个有序拷贝
nth_element 第 n 小元素归位 O(n) 平均 ❌ 中位数、分位数
is_sorted / is_sorted_until 判断/定位有序区间 O(n) - 预检
sort_heap 堆转有序序列 O(n log n) ❌ 堆排序收尾

比较器 :默认 std::less<>(升序),自定义传可调用对象,C++20 支持投影 std::ranges::sort(v, {}, &Member)。


4. 二分查找(要求有序区间)

算法 作用 返回值 复杂度
binary_search 判断是否存在 bool O(log n)
lower_bound 首个 ≥ val 的位置 迭代器 O(log n)
upper_bound 首个 > val 的位置 迭代器 O(log n)
equal_range 等值范围 [first, last) pair<iter, iter> O(log n)

典型用法:

cpp 复制代码
auto [first, last] = std::equal_range(v.begin(), v.end(), key);
if (first != last) { /* 存在 */ }
auto idx = std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), key)); // 插入位置/排名

5. 归并操作(要求输入有序)

算法 作用 复杂度
merge 归并两有序范围到输出 O(n+m)
inplace_merge 就地归并相邻两有序子范围 O(n log n) / O(n) 额外内存
includes 判断一个有序范围是否包含另一个 O(n+m)
set_union / set_intersection / set_difference / set_symmetric_difference 集合并/交/差/对称差 O(n+m)

输出迭代器需预留足够空间;set_* 算法对重复元素按最大/最小计数处理。


6. 堆操作(随机访问迭代器)

将区间视为最大堆(默认 less,顶端最大)。

算法 作用 复杂度
make_heap 建堆 O(n)
push_heap 插入元素(假设新元素已在末尾) O(log n)
pop_heap 取出堆顶(移至末尾) O(log n)
sort_heap 堆转有序序列 O(n log n)
is_heap / is_heap_until 判断/定位堆区间 O(n)

优先队列封装 :std::priority_queue 内部即用这组算法。


7. 极值操作

算法 作用 复杂度 C++ 版本
min / max 两值极值 O(1) C++98
minmax 同时返回极值对 O(1) C++11
min_element / max_element 区间极值位置 O(n) C++98
minmax_element 同时返回极值位置 O(1.5n) C++11
clamp 限制在区间 [lo, hi] O(1) C++17

minmax_element 单次遍历完成,比分别调用快 ~25%。


8. 字典序比较

算法 作用 复杂度
lexicographical_compare 字典序 < 判断 O(min(n,m))
lexicographical_compare_three_way 三路比较 (C++20) O(min(n,m))

用于容器/字符串的 < 重载实现。


9. 排列生成

算法 作用 复杂度 备注
next_permutation 生成下一字典序排列 O(n) 返回 false 表示已到末尾
prev_permutation 生成上一字典序排列 O(n) 配合 sort 可全排列枚举
is_permutation 判断排列关系 见 1. 已列在非修改操作

全排列模板:

cpp 复制代码
std::sort(v.begin(), v.end());
do {
    process(v);
} while (std::next_permutation(v.begin(), v.end()));

10. 数值算法 <numeric>

算法 作用 复杂度 C++ 版本
accumulate 左折叠求和/累积 O(n) C++98
reduce 并行可折叠求和 O(n) C++17
transform_reduce 映射后折叠 O(n) C++17
inner_product 内积/广义折叠 O(n) C++98
transform_inclusive_scan / transform_exclusive_scan 变换前缀和 O(n) C++17
inclusive_scan / exclusive_scan 前缀和(含/不含当前) O(n) C++17
partial_sum 就地前缀和 O(n) C++98
adjacent_difference 相邻差分 O(n) C++98
iota 填充递增序列 O(n) C++11
gcd / lcm 最大公约数/最小公倍数 O(log min(a,b)) C++17
midpoint / lerp 中点/线性插值 O(1) C++20

并行版本 :C++17 起在 <execution> 头下提供 std::execution::par 策略,如 std::reduce(std::execution::par, v.begin(), v.end()) 自动并行化。


11. C++20 Ranges 算法增强

#include <algorithm> → std::ranges 命名空间,主要改进:

  1. 直接接受范围 :ranges::sort(v) 无需 begin/end。
  2. 投影 :ranges::sort(employees, {}, &Employee::salary)。
  3. 组合视图 :v | views::filter(pred) | views::transform(op) 惰性管道,配合 ranges::to<vector>() 落地。
  4. 借用迭代器 :borrowed_iterator_t 避免悬垂。
  5. 新算法 :ranges::starts_with、ends_with、contains、find_last、fold_left、fold_right 等。

示例:Top-K 去重并按得分降序

cpp 复制代码
auto topk = data
    | views::filter([](auto& e){ return e.valid; })
    | views::transform(&Entry::score)
    | ranges::to<std::vector>();
ranges::sort(topk, std::greater{});
topk.erase(ranges::unique(topk).begin(), topk.end());
if (topk.size() > K) topk.resize(K);

12. 实战模式速查

需求 推荐组合
去重 sort → erase(unique(...), end)
Top-K nth_element(begin, begin+K, end) → sort(begin, begin+K)
中位数 nth_element(begin, begin+n/2, end)
计数排序(小整数域) counting_sort 手写或 transform_reduce 直方图
多键排序 sort + 自定义比较器或 tie:[](a,b){ return tie(a.x,a.y) < tie(b.x,b.y); }
流式处理/内存受限 views 管道 + ranges::fold_left / 输出迭代器
并行加速 <execution> + reduce/transform_reduce/sort(数据量大、操作无副作用)

13. 常见坑与最佳实践

坑 说明 规避
remove 不删除 只覆盖,返回新逻辑末尾 v.erase(remove(...), v.end())
unique 需有序 只能去相邻重复 先 sort 再 unique
比较器严格弱序 必须满足不可反、传递性 别写 a <= b,用 a < b
迭代器失效 vector 扩容/擦除会失效 用索引或 list/稳定容器
binary_search 只返回 bool 需位置用 lower_bound 配合 equal_range 取范围
accumulate 初值类型决定推导 0 导致整数溢出/截断 显式 0.0 或 T{}
并行算法数据竞争 lambda 捕获引用/副作用 保证纯函数、线程局部存储再归约
C++20 ranges 需 -std=c++20 且库支持 GCC≥10, Clang≥13, MSVC≥19.28 检查 __cpp_lib_ranges

14. 复杂度速查表(核心算法)

算法 最好 平均 最坏 空间
sort O(n log n) O(n log n) O(n log n) O(log n)
stable_sort O(n log n) O(n log n) O(n log² n) O(n)
nth_element O(n) O(n) O(n²) O(log n)
merge O(n+m) O(n+m) O(n+m) O(n+m) 输出
inplace_merge O(n) O(n log n) O(n log n) O(n) / O(1)
make_heap O(n) O(n) O(n) O(1)
binary_search O(1) O(log n) O(log n) O(1)
set_union/intersection O(n+m) O(n+m) O(n+m) O(n+m) 输出

15. 扩展阅读

  • C++ 参考 :https://en.cppreference.com/w/cpp/algorithm
  • 《Effective STL》 Item 43--51 算法选用准则
  • 《C++20 标准库》 Rainer Grimm,Ranges 章节
  • Abseil / Boost.Range / Range-v3 补充算法与视图

一句话总结:熟练掌握「排序/分区/二分/归并/堆/数值」六大核心族群,配合 C++20 Ranges 与并行执行策略,即可覆盖 95% 以上工程场景的算法需求。

相关推荐
冻柠檬飞冰走茶1 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
雪落漂泊1 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
不会算法的笨小孩3 小时前
异常的使用以及会出现的问题
开发语言·c++·c++11·异常
LabVIEW开发3 小时前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
严肃小白兔4 小时前
MATLAB 数值计算中的精度与误差问题:浮点运算、误差传播与数值稳定性
人工智能·算法·matlab
Hhy_11075 小时前
《C++深度解构06》手撕 string —— 从底层内存管理到深浅拷贝彻底吃透
c语言·开发语言·c++·学习·visual studio
青少儿编程课堂5 小时前
蓝桥杯青少组图形化省考报名倒计时·全国青少年信息素养大赛·电子学会图形化考级:校园黑白棋人机对战解析
c++·python·算法·bfs·信息学竞赛
YSL0701245 小时前
C++基础
开发语言·c++
eggwyw6 小时前
关于C++为什么不加入垃圾回收机制解析
开发语言·c++