跳到主要内容C++ 标准库算法实用手册 | 极客日志C++算法
C++ 标准库算法实用手册
一份面向日常开发的 C++ 标准库算法速查手册,按非修改、修改、排序、堆、数值等类别整理了常用函数,附带简洁示例和易错提醒。覆盖 find、count、for_each、copy、transform、remove/erase 惯用法、sort 与 stable_sort 选择、二分查找前提、堆操作以及 accumulate、iota 等数值接口,最后点明 remove 配合 erase、已排序要求等常见陷阱。
时间旅人2 浏览 非修改序列算法
这类算法不会动容器里的元素。
find 与 find_if
find 找第一个等于给定值的元素,find_if 用谓词筛选,find_end 找子序列最后一次出现的位置。
vector<int> nums = {1, 3, 5, 7, 9};
auto it = find(nums.begin(), nums.end(), 5);
if (it != nums.end()) cout << "found: " << *it << endl;
auto it2 = find_if(nums.begin(), nums.end(), [](int x) { return x > 6; });
cout << "first >6: " << *it2 << endl;
vector<int> sub = {3, 5};
auto it3 = find_end(nums.begin(), nums.end(), sub.begin(), sub.end());
if (it3 != nums.end())
cout << "subsequence starts at index: " << it3 - nums.begin() << endl;
count 与 count_if
count 统计等于某个值的元素个数,count_if 统计满足条件的个数。
vector<int> vec = {1, 2, , , , };
cnt = (vec.(), vec.(), );
even_cnt = (vec.(), vec.(), []( x) { x % == ; });
3
2
4
2
int
count
begin
end
2
int
count_if
begin
end
int
return
2
0
for_each
对范围内每个元素执行一个操作。注意传入的函数可能会修改元素,比如下面这个把每个数翻倍。
vector<int> vec = {1, 2, 3, 4, 5};
for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; });
equal 与 mismatch
equal 比较两个区间是否完全相同;mismatch 返回第一处不匹配的位置对。
vector<int> a = {1, 2, 3};
vector<int> b = {1, 2, 4};
vector<int> c = {1, 2, 3, 4};
bool is_equal = equal(a.begin(), a.end(), b.begin());
cout << "a == b? " << boolalpha << is_equal << endl;
auto mis = mismatch(a.begin(), a.end(), c.begin());
if (mis.first != a.end())
cout << "mismatch: " << *mis.first << " vs " << *mis.second << endl;
all_of, any_of, none_of
这三个函数用来快速判断区间内元素是否全部、存在、或没有满足某个条件。
vector<int> vec = {2, 4, 6, 8};
bool all_even = all_of(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
bool any_odd = any_of(vec.begin(), vec.end(), [](int x) { return x % 2 != 0; });
bool none_negative = none_of(vec.begin(), vec.end(), [](int x) { return x < 0; });
修改序列算法
copy 与 copy_if
copy 把整个区间拷贝到目标位置,copy_if 只拷贝满足条件的元素。如果目标没有足够空间,用 back_inserter 更方便——它会自动调用 push_back,不用提前分配。
vector<int> src = {1, 2, 3, 4, 5};
vector<int> dest(5);
copy(src.begin(), src.end(), dest.begin());
vector<int> evens;
copy_if(src.begin(), src.end(), back_inserter(evens), [](int x) { return x % 2 == 0; });
transform
对区间内每个元素应用一个函数,结果存到另一个区间。可以一元或二元操作。
vector<int> nums = {1, 2, 3};
vector<int> squares(3);
transform(nums.begin(), nums.end(), squares.begin(), [](int x) { return x * x; });
vector<int> a = {1, 2, 3};
vector<int> b = {4, 5, 6};
vector<int> sum(3);
transform(a.begin(), a.end(), b.begin(), sum.begin(), [](int x, int y) { return x + y; });
replace 系列
replace 把旧值换成新值,replace_if 按条件替换,replace_copy 则在拷贝的同时进行替换,原容器不变。
vector<int> nums = {1, 2, 3, 2, 5};
replace(nums.begin(), nums.end(), 2, 20);
replace_if(nums.begin(), nums.end(), [](int x) { return x > 10; }, 0);
vector<int> res;
replace_copy(nums.begin(), nums.end(), back_inserter(res), 3, 300);
remove 与 erase 的经典组合
remove 并不真正删除元素,只是把要删的元素挪到末尾,返回新的逻辑结尾迭代器;必须配合 erase 才能物理删除。很多人第一次都会忘记。
vector<int> nums = {1, 2, 3, 2, 4};
auto new_end = remove(nums.begin(), nums.end(), 2);
nums.erase(new_end, nums.end());
nums = {1, 2, 3, 4, 5};
nums.erase(remove_if(nums.begin(), nums.end(), [](int x) { return x % 2 == 0; }), nums.end());
unique
移除相邻的重复元素,同样返回新的逻辑尾迭代器,一般也要接 erase。
vector<int> vec = {1, 1, 2, 2, 3, 3, 3, 4, 5};
auto last = unique(vec.begin(), vec.end());
vec.erase(last, vec.end());
reverse 与 rotate
reverse 直接反转区间;rotate 把区间旋转,让中间元素成为新的起点。
vector<int> vec = {1, 2, 3, 4, 5};
reverse(vec.begin(), vec.end());
vec = {1, 2, 3, 4, 5};
rotate(vec.begin(), vec.begin() + 2, vec.end());
shuffle
随机打乱,需要提供一个随机数生成器。C++11 之后推荐用 random_device 和 mt19937。
#include <random>
#include <algorithm>
vector<int> vec = {1, 2, 3, 4, 5};
random_device rd;
mt19937 g(rd());
shuffle(vec.begin(), vec.end(), g);
排序相关算法
sort、stable_sort 与 partial_sort
sort 默认升序,底层通常是 introsort,不稳定;stable_sort 保证相等元素相对顺序不变,空间开销稍大;partial_sort 只把最小的几个元素排到前面。
vector<int> vec = {5, 3, 1, 4, 2};
sort(vec.begin(), vec.end());
sort(vec.begin(), vec.end(), greater<int>());
vector<pair<int, int>> vec2 = {{1, 2}, {2, 1}, {1, 1}, {2, 2}};
stable_sort(vec2.begin(), vec2.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
vec = {5, 3, 1, 4, 2, 6};
partial_sort(vec.begin(), vec.begin() + 3, vec.end());
nth_element
把第 n 小的元素放在正确位置,左边都不大于它,右边都不小于。复杂度 O(n)。
vector<int> vec = {5, 3, 1, 4, 2, 6};
nth_element(vec.begin(), vec.begin() + 2, vec.end());
二分查找系列(必须已排序)
binary_search 只返回 bool,lower_bound 返回第一个不小于目标的迭代器,upper_bound 返回第一个大于目标的迭代器。
vector<int> sorted = {1, 3, 3, 5, 7};
bool exists = binary_search(sorted.begin(), sorted.end(), 3);
auto lb = lower_bound(sorted.begin(), sorted.end(), 3);
auto ub = upper_bound(sorted.begin(), sorted.end(), 3);
merge
vector<int> a = {1, 3, 5};
vector<int> b = {2, 4, 6};
vector<int> merged(a.size() + b.size());
merge(a.begin(), a.end(), b.begin(), b.end(), merged.begin());
堆算法
vector<int> vec = {4, 1, 3, 2, 5};
make_heap(vec.begin(), vec.end());
vec.push_back(6);
push_heap(vec.begin(), vec.end());
pop_heap(vec.begin(), vec.end());
int max_val = vec.back(); vec.pop_back();
sort_heap(vec.begin(), vec.end());
最小/最大值算法
min 和 max
int a = 5, b = 3;
int m = min(a, b);
int M = max(a, b);
auto min_list = min({4, 2, 8, 5, 1});
auto max_list = max({4, 2, 8, 5, 1});
min_element 与 max_element
vector<int> vec = {3, 1, 4, 2, 5};
auto min_it = min_element(vec.begin(), vec.end());
auto max_it = max_element(vec.begin(), vec.end());
minmax_element (C++11)
vector<int> vec = {3, 1, 4, 2, 5};
auto minmax = minmax_element(vec.begin(), vec.end());
数值算法()
accumulate
#include <numeric>
vector<int> vec = {1, 2, 3, 4, 5};
int sum = accumulate(vec.begin(), vec.end(), 0);
int product = accumulate(vec.begin(), vec.end(), 1, multiplies<int>());
inner_product
vector<int> a = {1, 2, 3};
vector<int> b = {4, 5, 6};
int dot = inner_product(a.begin(), a.end(), b.begin(), 0);
iota
vector<int> vec(5);
iota(vec.begin(), vec.end(), 10);
partial_sum
vector<int> src = {1, 2, 3, 4, 5};
vector<int> dst(src.size());
partial_sum(src.begin(), src.end(), dst.begin());
adjacent_difference
vector<int> src = {1, 2, 3, 4, 5};
vector<int> dst(src.size());
adjacent_difference(src.begin(), src.end(), dst.begin());
其他常用算法
generate 与 generate_n
vector<int> vec(5);
int n = 0;
generate(vec.begin(), vec.end(), [&n]() { return n++; });
vector<int> vec2(5);
n = 10;
generate_n(vec2.begin(), 3, [&n]() { return n++; });
includes
检查一个排序区间是否包含另一个排序区间的所有元素。
vector<int> v1 = {1,2,3,4,5};
vector<int> v2 = {2,4};
bool inc = includes(v1.begin(), v1.end(), v2.begin(), v2.end());
集合操作
vector<int> v1 = {1,2,3,4,5};
vector<int> v2 = {3,4,5,6,7};
vector<int> res;
set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res));
res.clear();
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res));
res.clear();
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res));
res.clear();
set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(res));
几个容易踩的坑
sort vs stable_sort:sort 是 introsort,不稳定;stable_sort 基于归并排序,稳定但内存占用稍高。如果你依赖相等元素的相对顺序,就得用 stable_sort。
remove 要配合 erase:remove 只是把要删除的元素挪到末尾并返回新终点,容器大小不变。单独用 remove 会留下垃圾元素,典型写法是 vec.erase(remove(vec.begin(), vec.end(), val), vec.end())。
要求已排序的算法:二分查找系列、集合算法、merge 等都要求输入区间有序,否则结果未定义。使用前务必 sort 一下。
相关免费在线工具
- 加密/解密文本
使用加密算法(如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