跳到主要内容C++ STL 常用算法实战与解析 | 极客日志C++算法
C++ STL 常用算法实战与解析
综述由AI生成C++ STL 算法库涵盖查找、统计、排序、数值计算及集合操作等核心功能。本文详细解析了非修改与修改序列算法的使用细节,重点说明了 remove 与 erase 的配合机制、排序算法的稳定性差异以及二分查找对有序性的要求。通过实际代码示例展示了 transform、partial_sort 等高频用法,帮助开发者提升代码效率与可读性。
星落2 浏览 1. 非修改序列算法
这类算法最大的特点是不会改变容器内的元素,主要用于查询和统计。在实际开发中,我们最常接触的就是查找和计数。
1.1 查找:find 系列
std::find 用于查找第一个等于指定值的元素,返回迭代器;若未找到则返回 end()。配合 lambda 表达式的 find_if 则能处理更复杂的条件。
#include <vector>
#include <algorithm>
#include <iostream>
std::vector<int> nums = {1, 3, 5, 7, 9};
auto it = std::find(nums.begin(), nums.end(), 5);
if (it != nums.end()) {
std::cout << "found: " << *it << std::endl;
}
auto it2 = std::find_if(nums.begin(), nums.end(), [](int x) { return x > 6; });
std::cout << "first >6: " << *it2 << std::endl;
std::vector<int> sub = {3, 5};
auto it3 = std::find_end(nums.begin(), nums.end(), sub.begin(), sub.end());
(it3 != nums.()) {
std::cout << << (it3 - nums.()) << std::endl;
}
if
end
"subsequence starts at index: "
begin
1.2 统计:count 系列
std::count 统计特定值出现的次数,而 count_if 则基于谓词统计满足条件的元素个数。
std::vector<int> vec = {1, 2, 3, 2, 4, 2};
int cnt = std::count(vec.begin(), vec.end(), 2);
int even_cnt = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
1.3 遍历:for_each
虽然现代 C++ 更多使用范围 for 循环,但 for_each 在需要传递函数对象或 Lambda 时依然很有用,它会对范围内每个元素应用一个函数。
std::vector<int> vec = {1, 2, 3, 4, 5};
std::for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; });
1.4 比较:equal 与 mismatch
判断两个范围是否相等,或者找出第一个不匹配的位置。
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 4};
bool is_equal = std::equal(a.begin(), a.end(), b.begin());
std::cout << "a == b? " << std::boolalpha << is_equal << std::endl;
auto mis = std::mismatch(a.begin(), a.end(), b.begin());
if (mis.first != a.end()) {
std::cout << "mismatch: " << *mis.first << " vs " << *mis.second << std::endl;
}
1.5 逻辑检查:all_of, any_of, none_of
这三个算法常用于验证数据是否符合某种规则,比如检查数组是否全为正数。
std::vector<int> vec = {2, 4, 6, 8};
bool all_even = std::all_of(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
bool any_odd = std::any_of(vec.begin(), vec.end(), [](int x) { return x % 2 != 0; });
bool none_negative = std::none_of(vec.begin(), vec.end(), [](int x) { return x < 0; });
2. 修改序列算法
这部分算法会直接操作容器内容,使用时需特别注意容器的空间管理。
2.1 复制:copy 与 copy_if
std::copy 是基础复制,copy_if 则支持条件过滤。注意目标容器必须预留足够空间,或使用 back_inserter。
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(5);
std::copy(src.begin(), src.end(), dest.begin());
std::vector<int> evens;
std::copy_if(src.begin(), src.end(), std::back_inserter(evens), [](int x) { return x % 2 == 0; });
2.2 变换:transform
将源范围的数据通过函数转换后存入目标范围。支持单参数(如平方)或多参数(如两向量相加)。
std::vector<int> nums = {1, 2, 3};
std::vector<int> squares(3);
std::transform(nums.begin(), nums.end(), squares.begin(), [](int x) { return x * x; });
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
std::vector<int> sum(3);
std::transform(a.begin(), a.end(), b.begin(), sum.begin(), [](int x, int y) { return x + y; });
2.3 替换:replace 系列
replace 原地替换值,replace_copy 则在复制过程中替换,保留原数据不变。
std::vector<int> nums = {1, 2, 3, 2, 5};
std::replace(nums.begin(), nums.end(), 2, 20);
std::vector<int> res;
std::replace_copy(nums.begin(), nums.end(), std::back_inserter(res), 3, 300);
2.4 移除:remove 与 erase
这是新手最容易踩坑的地方。remove 只是逻辑上把元素移到末尾并返回新尾迭代器,并不真正删除内存。必须配合 erase 才能释放空间。
std::vector<int> nums = {1, 2, 3, 2, 4};
auto new_end = std::remove(nums.begin(), nums.end(), 2);
nums.erase(new_end, nums.end());
nums = {1, 2, 3, 4, 5};
nums.erase(std::remove_if(nums.begin(), nums.end(), [](int x) { return x % 2 == 0; }), nums.end());
2.5 去重与重排
unique 移除连续重复元素,同样需要配合 erase。reverse、rotate 和 shuffle 则分别用于反转、旋转和随机打乱顺序。
std::vector<int> vec = {1, 1, 2, 2, 3};
auto last = std::unique(vec.begin(), vec.end());
vec.erase(last, vec.end());
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(vec.begin(), vec.end(), g);
3. 排序和相关算法
3.1 排序:sort 与 stable_sort
std::sort 通常最快但不稳定,stable_sort 保证相等元素相对位置不变。partial_sort 适合只需要前 N 个有序元素的场景。
std::vector<int> vec = {5, 3, 1, 4, 2};
std::sort(vec.begin(), vec.end());
std::sort(vec.begin(), vec.end(), std::greater<int>());
std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());
3.2 分区:nth_element
快速找到第 N 小的元素,并将小于它的放左边,大于的放右边,时间复杂度优于完全排序。
std::vector<int> vec = {5, 3, 1, 4, 2, 6};
std::nth_element(vec.begin(), vec.begin() + 2, vec.end());
3.3 二分查找:binary_search 等
这些算法要求容器必须是已排序的。lower_bound 和 upper_bound 比单纯的 binary_search 更有用,因为它们返回迭代器而非布尔值。
std::vector<int> sorted = {1, 3, 3, 5, 7};
auto lb = std::lower_bound(sorted.begin(), sorted.end(), 3);
auto ub = std::upper_bound(sorted.begin(), sorted.end(), 3);
3.4 合并:merge
std::vector<int> a = {1, 3, 5};
std::vector<int> b = {2, 4, 6};
std::vector<int> merged(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), merged.begin());
4. 堆算法
STL 提供了基于堆的操作接口,常用于优先队列实现。
std::vector<int> vec = {4, 1, 3, 2, 5};
std::make_heap(vec.begin(), vec.end());
vec.push_back(6);
std::push_heap(vec.begin(), vec.end());
std::pop_heap(vec.begin(), vec.end());
int max_val = vec.back();
vec.pop_back();
std::sort_heap(vec.begin(), vec.end());
5. 数值计算算法
- accumulate: 累加或自定义运算。
- inner_product: 内积计算。
- iota: 填充递增序列。
- partial_sum / adjacent_difference: 前缀和与差分。
#include <numeric>
std::vector<int> vec = {1, 2, 3, 4, 5};
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::vector<int> dst(vec.size());
std::partial_sum(vec.begin(), vec.end(), dst.begin());
6. 集合操作
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {3, 4, 5, 6, 7};
std::vector<int> result;
std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
7. 常见问题速查
-
sort 与 stable_sort 的区别?
sort 速度快但不稳定,stable_sort 慢一点但保持相等元素顺序。如果稳定性重要,务必选后者。
-
为什么 remove 需要配合 erase?
remove 只是移动元素并返回新逻辑尾部,容器大小不变。只有调用 erase 才能真正销毁多余元素并更新 size。
-
哪些算法依赖有序性?
二分查找类 (binary_search, lower_bound)、集合操作 (set_union 等) 以及 merge,使用前请确保数据已排序。
掌握这些算法能让代码更简洁高效,减少手写循环带来的 bug。建议在实际项目中多尝试组合使用。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online