C++ STL算法
一、STL算法概述
1. 算法分类体系
- 非修改序列算法:不改变容器内容(如find、count)
- 修改序列算法:改变容器内容(如copy、transform)
- 排序及相关操作:排序、合并、搜索(如sort、merge)
- 数值算法:数学运算(如accumulate、inner_product)
2. 算法通用特性
- 基于迭代器工作,不直接操作容器
- 大多数算法在
<algorithm>头文件中定义 - 数值算法在
<numeric>中定义 - 并行版本(C++17)在
<execution>中定义
二、非修改序列算法
1. 查找算法
// 基本查找
auto it = std::find(v.begin(), v.end(), value);
// 条件查找
auto it = std::find_if(v.begin(), v.end(), [](auto& x) {
return x > 10;
});
// 查找子序列
auto pos = std::search(v1.begin(), v1.end(), v2.begin(), v2.end());
// 其他查找
std::adjacent_find // 查找相邻重复元素
std::find_first_of // 查找集合中任意元素首次出现
std::find_end // 查找子序列最后一次出现
2. 统计与比较
// 计数
int cnt = std::count(v.begin(), v.end(), value);
int cnt = std::count_if(v.begin(), v.end(), pred);
// 比较
bool equal = std::equal(v1.begin(), v1.end(), v2.begin());
auto mismatch = std::mismatch(v1.begin(), v1.end(), v2.begin());
// 检查条件
bool all = std::all_of(v.begin(), v.end(), pred);
bool any = std::any_of(v.begin(), v.end(), pred);
bool none = std::none_of(v.begin(), v.end(), pred);
三、修改序列算法
1. 拷贝与移动
// 基本拷贝
std::copy(src.begin(), src.end(), dest.begin());
// 条件拷贝
std::copy_if(src.begin(), src.end(), dest.begin(), pred);
// 反向拷贝
std::copy_backward(src.begin(), src.end(), dest.end());
// 移动元素(C++11)
std::move(src.begin(), src.end(), dest.begin());
2. 填充与生成
// 填充
std::fill(v.begin(), v.end(), value);
std::fill_n(v.begin(), 5, value); // 填充前n个
// 生成
std::generate(v.begin(), v.end(), [](){
return rand() % 100;
});
// iota生成序列(C++11)
std::iota(v.begin(), v.end(), 10); // 10,11,12...
3. 替换与变换
// 替换
std::replace(v.begin(), v.end(), old_val, new_val);
std::replace_if(v.begin(), v.end(), pred, new_val);
// 变换
std::transform(v1.begin(), v1.end(), v2.begin(),
[](auto x){ return x * 2; });
// 二元变换
std::transform(v1.begin(), v1.end(), v2.begin(),
v3.begin(), std::plus<int>());
4. 删除算法
// 移除元素(逻辑删除,返回新end)
auto new_end = std::remove(v.begin(), v.end(), value);
auto new_end = std::remove_if(v.begin(), v.end(), pred);
// 实际删除(erase-remove惯用法)
v.erase(std::remove(v.begin(), v.end(), value), v.end());
// 去重
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
四、排序及相关算法
1. 基本排序
// 快速排序(不稳定)
std::sort(v.begin(), v.end());
std::sort(v.begin(), v.end(), std::greater<int>());
// 稳定排序
std::stable_sort(v.begin(), v.end());
// 部分排序
std::partial_sort(v.begin(), v.begin()+5, v.end()); // 前5个有序
2. 选择算法
// 第n大元素
std::nth_element(v.begin(), v.begin()+n, v.end());
// 分区
auto it = std::partition(v.begin(), v.end(), pred);
auto it = std::stable_partition(v.begin(), v.end(), pred);
// 划分点(已分区范围)
auto it = std::partition_point(v.begin(), v.end(), pred);
3. 合并与堆操作
// 合并有序序列
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());
// 堆操作
std::make_heap(v.begin(), v.end());
std::push_heap(v.begin(), v.end());
std::pop_heap(v.begin(), v.end());
v.pop_back(); // 实际移除
五、数值算法
1. 基础数值运算
#include <numeric>
// 累加
int sum = std::accumulate(v.begin(), v.end(), 0);
int sum = std::accumulate(v.begin(), v.end(), 1,
[](int a, int b){ return a * b; });
// 内积
int product = std::inner_product(v1.begin(), v1.end(),
v2.begin(), 0);
// 相邻差
std::adjacent_difference(v.begin(), v.end(), result.begin());
// 部分和
std::partial_sum(v.begin(), v.end(), result.begin());
2. 广义数值运算
// 约简(C++17)
auto result = std::reduce(v.begin(), v.end());
// 变换约简(C++17)
auto sum = std::transform_reduce(v.begin(), v.end(),
0, std::plus<>(), [](auto x){ return x*x; });
// 扫描(C++17)
std::inclusive_scan(v.begin(), v.end(), result.begin());
std::exclusive_scan(v.begin(), v.end(), result.begin(), 0);
六、C++17/20新特性
1. 并行算法
#include <execution>
// 并行策略
std::sort(std::execution::par, v.begin(), v.end());
std::for_each(std::execution::par_unseq, v.begin(), v.end(), f);
// 可用策略
- seq : 顺序执行
- par : 并行执行
- par_unseq: 并行+向量化
2. 约束算法(C++20)
#include <ranges>
// 范围版本算法
std::ranges::sort(v);
auto it = std::ranges::find(v, value);
// 管道语法
auto result = v | std::views::filter(pred)
| std::views::transform(f);
七、算法高级技巧
1. 迭代器适配器
#include <iterator>
// 反向迭代
std::copy(v.rbegin(), v.rend(), std::ostream_iterator<int>(cout, " "));
// 插入迭代器
std::fill_n(std::back_inserter(v), 5, 42);
// 流迭代器
std::copy(std::istream_iterator<int>(cin),
std::istream_iterator<int>(),
std::back_inserter(v));
2. 算法组合模式
// 查找转换模式
auto it = std::find_if(v.begin(), v.end(), pred);
if (it != v.end()) {
*it = transform(*it);
}
// 擦除-唯一模式
v.erase(std::unique(v.begin(), v.end()), v.end());
// 分区-排序模式
auto mid = std::partition(v.begin(), v.end(), pred);
std::sort(v.begin(), mid);
八、性能优化指南
1. 算法复杂度对比
| 算法 | 平均复杂度 | 适用场景 |
|---|---|---|
| std::find | O(n) | 线性搜索 |
| std::binary_search | O(log n) | 已排序范围 |
| std::sort | O(n log n) | 通用排序 |
| std::stable_sort | O(n log n) | 需要稳定性 |
| std::partial_sort | O(n log k) | TopK问题 |
| std::nth_element | O(n) | 中位数/百分位 |
2. 选择优化策略
-
小数据量:
- 使用线性算法(避免排序开销)
- 简单排序(插入排序)
-
大数据量:
- 优先使用O(n log n)算法
- 考虑并行执行(C++17)
-
特定场景:
- 已排序范围使用binary_search
- 去重先排序后unique
九、常见问题与陷阱
1. 迭代器失效
// 错误示例(在循环中删除)
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it % 2 == 0) {
v.erase(it); // 危险!it失效
}
}
// 正确做法
auto new_end = std::remove_if(v.begin(), v.end(),
[](int x){ return x % 2 == 0; });
v.erase(new_end, v.end());
2. 谓词要求
// 纯函数要求(无状态)
bool pred(int x) {
static int count = 0; // 危险!
return x > count++;
}
// 排序严格弱序
bool compare(int a, int b) {
return a <= b; // 错误!必须用 <
}
十、自定义算法实现
1. 实现通用算法模板
template <typename InputIt, typename UnaryPredicate>
InputIt my_find_if(InputIt first, InputIt last, UnaryPredicate pred) {
for (; first != last; ++first) {
if (pred(*first)) {
return first;
}
}
return last;
}
2. 算法策略模式
template <typename RandIt, typename Compare>
void my_sort(RandIt first, RandIt last, Compare comp) {
if (last - first <= 40) {
insertion_sort(first, last, comp);
} else {
quick_sort(first, last, comp);
}
}
掌握STL算法需要:
- 理解每种算法的适用场景和复杂度
- 熟悉迭代器和函数对象的使用
- 掌握现代C++的并行和范围特性
- 避免常见陷阱和错误用法
- 能够组合算法解决复杂问题