C++ 笔记:迭代器与算法:STL 算法库的使用
发布于:
前言
STL 算法库是 C++ 标准库的核心,提供了丰富的通用算法。理解迭代器和算法的配合使用,是写出高效、优雅 C++ 代码的关键。本文将从迭代器分类、常用算法、自定义算法等多个维度深入解析 STL 算法库,帮助读者全面理解这一重要组件。
1. 迭代器基础
1.1 迭代器分类
迭代器分为五类,从弱到强:
- 输入迭代器(Input Iterator):只能读取,只能向前
- 输出迭代器(Output Iterator):只能写入,只能向前
- 前向迭代器(Forward Iterator):可以读写,只能向前
- 双向迭代器(Bidirectional Iterator):可以向前向后
- 随机访问迭代器(Random Access Iterator):可以任意跳转
1.2 迭代器特性
#include <iterator>
// 获取迭代器类型
using iter_type = std::iterator_traits<std::vector<int>::iterator>::iterator_category;
// 检查迭代器类型
static_assert(std::is_same_v<iter_type, std::random_access_iterator_tag>);
2. 常用算法
2.1 查找算法
#include <algorithm>
std::vector<int> vec = {1, 2, 3, 4, 5};
// find:查找值
auto it = std::find(vec.begin(), vec.end(), 3);
// find_if:查找满足条件的元素
auto it2 = std::find_if(vec.begin(), vec.end(),
[](int x) { return x > 3; });
// binary_search:二分查找(需要有序)
bool found = std::binary_search(vec.begin(), vec.end(), 3);
2.2 计数算法
// count:计数等于值的元素
int count = std::count(vec.begin(), vec.end(), 3);
// count_if:计数满足条件的元素
int count_if = std::count_if(vec.begin(), vec.end(),
[](int x) { return x > 3; });
2.3 变换算法
// transform:转换元素
std::vector<int> result;
std::transform(vec.begin(), vec.end(), std::back_inserter(result),
[](int x) { return x * 2; });
// for_each:对每个元素执行操作
std::for_each(vec.begin(), vec.end(),
[](int& x) { x *= 2; });
2.4 排序算法
// sort:排序
std::sort(vec.begin(), vec.end());
// partial_sort:部分排序
std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());
// nth_element:找到第 n 大的元素
std::nth_element(vec.begin(), vec.begin() + 2, vec.end());
3. 算法与迭代器配合
3.1 输入/输出迭代器
// 从输入流读取
std::vector<int> vec;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(vec));
// 输出到流
std::copy(vec.begin(), vec.end(),
std::ostream_iterator<int>(std::cout, " "));
3.2 插入迭代器
// back_inserter:尾部插入
std::vector<int> result;
std::copy(vec.begin(), vec.end(), std::back_inserter(result));
// front_inserter:头部插入(需要支持 push_front)
std::list<int> lst;
std::copy(vec.begin(), vec.end(), std::front_inserter(lst));
// inserter:指定位置插入
std::set<int> s;
std::copy(vec.begin(), vec.end(), std::inserter(s, s.begin()));
4. 算法组合
4.1 管道式编程
// 组合多个算法
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 过滤、转换、收集
std::vector<int> result;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(result),
[](int x) { return x % 2 == 0; });
std::transform(result.begin(), result.end(), result.begin(),
[](int x) { return x * x; });
4.2 范围算法(C++20)
#include <ranges>
// 使用范围视图
auto even_squares = vec
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; });
for (auto value : even_squares) {
std::cout << value << " ";
}
5. 自定义算法
5.1 实现通用算法
template<typename InputIt, typename UnaryPredicate>
bool all_of(InputIt first, InputIt last, UnaryPredicate pred) {
for (; first != last; ++first) {
if (!pred(*first)) {
return false;
}
}
return true;
}
5.2 算法特化
// 为特定容器类型特化
template<typename T>
void sort_optimized(std::vector<T>& vec) {
if (vec.size() < 100) {
// 小数组使用插入排序
insertion_sort(vec.begin(), vec.end());
} else {
// 大数组使用快速排序
std::sort(vec.begin(), vec.end());
}
}
6. 性能考虑
6.1 算法复杂度
不同算法有不同的复杂度:
std::find:O(n)std::binary_search:O(log n)(需要有序)std::sort:O(n log n)std::nth_element:O(n)
6.2 优化技巧
// 预分配空间
std::vector<int> result;
result.reserve(vec.size()); // 避免多次重新分配
// 使用移动语义
std::move(vec.begin(), vec.end(), result.begin());
7. 实际应用
7.1 数据处理管道
// 读取、过滤、转换、输出
std::vector<int> data;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(data));
data.erase(std::remove_if(data.begin(), data.end(),
[](int x) { return x < 0; }),
data.end());
std::transform(data.begin(), data.end(), data.begin(),
[](int x) { return x * 2; });
std::copy(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, "\n"));
7.2 容器操作
// 合并两个有序容器
std::vector<int> vec1 = {1, 3, 5};
std::vector<int> vec2 = {2, 4, 6};
std::vector<int> merged;
std::merge(vec1.begin(), vec1.end(),
vec2.begin(), vec2.end(),
std::back_inserter(merged));
8. 最佳实践
8.1 优先使用算法而非循环
// 推荐:使用算法
auto it = std::find_if(vec.begin(), vec.end(),
[](int x) { return x > 10; });
// 不推荐:手写循环
for (auto it = vec.begin(); it != vec.end(); ++it) {
if (*it > 10) {
break;
}
}
8.2 使用 Lambda 表达式
// Lambda 使算法更灵活
std::sort(vec.begin(), vec.end(),
[](int a, int b) { return a > b; }); // 降序
9. 小结
STL 算法库提供了丰富的通用算法,配合迭代器可以实现高效的数据处理。
核心要点:
- 理解不同迭代器类型的能力
- 掌握常用算法的使用场景
- 学会组合多个算法
- 注意算法复杂度
- 优先使用算法而非手写循环
掌握 STL 算法库,可以写出更简洁、更高效的 C++ 代码。