跳到主要内容C++ STL 标准库算法详解与应用 | 极客日志C++算法
C++ STL 标准库算法详解与应用
系统讲解了 C++ STL 中的各类算法,涵盖非修改序列算法(find、count)、修改序列算法(copy、transform)、排序算法(sort、nth_element)、堆算法、最小最大值算法及数值算法。文章通过具体代码示例演示了各函数的用法、参数含义及返回值,并重点说明了 remove 需配合 erase 使用、二分查找类算法要求容器有序等关键细节。
LinuxPan1 浏览 1、非修改序列算法
这些算法不会改变它们所操作的容器中的元素。
1.1 find 和 find_if
find(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。
find_if(begin, end, predicate):查找第一个满足谓词的元素。
find_end(begin, end, sub_begin, sub_end):查找子序列最后一次出现的位置。
vector<> nums = {, , , , };
it = (nums.(), nums.(), );
(it != nums.()) {
cout << << *it << endl;
}
it2 = (nums.(), nums.(), []( x) { x > ; });
cout << << *it2 << endl;
vector<> sub = {, };
it3 = (nums.(), nums.(), sub.(), sub.());
(it3 != nums.()) {
cout << << it3 - nums.() << endl;
}
int
1
3
5
7
9
auto
find
begin
end
5
if
end
"found: "
auto
find_if
begin
end
int
return
6
"first >6: "
int
3
5
auto
find_end
begin
end
begin
end
if
end
"subsequence starts at index: "
begin
1.2 count 和 count_if
count(begin, end, value):统计等于 value 的元素个数。
count_if(begin, end, predicate):统计满足谓词(predicate)的元素个数。
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
std::vector<int> vec = {1, 2, 3, 4, 5};
std::for_each(vec.begin(), vec.end(), [](int& x) {
x *= 2;
});
1.4 equal 与 mismatch
equal(b1, e1, b2):判断两个范围 [b1,e1) 和 [b2, b2+(e1-b1)) 是否相等。
mismatch(b1, e1, b2):返回两个范围中第一个不相等元素的迭代器对(pair)。
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;
}
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
copy(begin, end, dest):将 [begin, end) 中的元素复制到 dest 开始的位置。
copy_if(begin, end, dest, predicate):复制满足谓词的元素到 dest。
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; });
注意:back_inserter(dest) 会自动调用 push_back,无需提前分配空间。
2.2 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; });
2.3 replace、replace_if 与 replace_copy
replace(begin, end, old_val, new_val):将所有 old_val 替换为 new_val。
replace_if(begin, end, predicate, new_val):替换满足谓词的元素。
replace_copy(begin, end, dest, old_val, new_val):复制时替换元素(不修改原容器)。
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);
2.4 remove、remove_if 与 erase
remove(begin, end, value):将等于 value 的元素'移动'到容器末尾,返回新的逻辑尾迭代器(不实际删除元素,需配合 erase)。
remove_if(begin, end, predicate):移动满足谓词的元素到末尾。
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());
2.5 unique
移除范围内连续的重复元素,返回新的逻辑结尾迭代器。通常与 erase 结合使用。
std::vector<int> vec = {1, 1, 2, 2, 3, 3, 3, 4, 5};
auto last = std::unique(vec.begin(), vec.end());
vec.erase(last, vec.end());
2.6 reverse
std::vector<int> vec = {1, 2, 3, 4, 5};
std::reverse(vec.begin(), vec.end());
2.7 rotate
std::vector<int> vec = {1, 2, 3, 4, 5};
std::rotate(vec.begin(), vec.begin() + 2, vec.end());
2.8 shuffle
随机重排范围内的元素(需要 C++11 或更高版本)
#include <random>
#include <algorithm>
std::vector<int> vec = {1, 2, 3, 4, 5};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(vec.begin(), vec.end(), g);
3、排序和相关算法
3.1 sort、stable_sort 与 partial_sort
sort(begin, end):对元素进行快速排序(不稳定,平均时间复杂度 O(n log n))。
stable_sort(begin, end):稳定排序(相等元素相对位置不变)。
partial_sort(begin, mid, end):部分排序,使 [begin, mid) 为整个范围中最小的元素并排序。
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::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });
std::vector<std::pair<int, int>> vec = {{1, 2}, {2, 1}, {1, 1}, {2, 2}};
std::stable_sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) { return a.first < b.first;
std::vector<int> vec = {5, 3, 1, 4, 2, 6};
std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());
3.2 nth_element
重新排列范围,使得指定位置的元素等于排序后的元素,并且左边的元素都不大于它,右边的元素都不小于它
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(begin, end, value):判断 value 是否存在(返回 bool)。
lower_bound(begin, end, value):返回第一个不小于 value 的元素迭代器。
upper_bound(begin, end, value):返回第一个大于 value 的元素迭代器。
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);
cout << "lower_bound index: " << lb - sorted.begin() << endl;
auto ub = upper_bound(sorted.begin(), sorted.end(), 3);
cout << "upper_bound index: " << ub - sorted.begin() << endl;
3.4 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());
4、堆算法
STL 提供了将范围作为堆来操作的算法,包括 make_heap, push_heap, pop_heap, sort_heap 等。
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、最小/最大值算法
5.1 min 和 max
int a = 5, b = 3;
int min_val = std::min(a, b);
int max_val = std::max(a, b);
auto min_of_list = std::min({4, 2, 8, 5, 1});
auto max_of_list = std::max({4, 2, 8, 5, 1});
5.2 min_element 和 max_element
std::vector<int> vec = {3, 1, 4, 2, 5};
auto min_it = std::min_element(vec.begin(), vec.end());
auto max_it = std::max_element(vec.begin(), vec.end());
5.3 minmax_element (C++11)
std::vector<int> vec = {3, 1, 4, 2, 5};
auto minmax = std::minmax_element(vec.begin(), vec.end());
6、数值算法(在中)
6.1 accumulate
#include <numeric>
std::vector<int> vec = {1, 2, 3, 4, 5};
int sum = std::accumulate(vec.begin(), vec.end(), 0);
int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
6.2 inner_product
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
int dot = std::inner_product(a.begin(), a.end(), b.begin(), 0);
6.3 iota
std::vector<int> vec(5);
std::iota(vec.begin(), vec.end(), 10);
6.4 partial_sum
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(src.size());
std::partial_sum(src.begin(), src.end(), dst.begin());
6.5 adjacent_difference
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(src.size());
std::adjacent_difference(src.begin(), src.end(), dst.begin());
7、其他
7.1 generate
std::vector<int> vec(5);
int n = 0;
std::generate(vec.begin(), vec.end(), [&n]() { return n++; });
7.2 generate_n
std::vector<int> vec(5);
int n = 10;
std::generate_n(vec.begin(), 3, [&n]() { return n++; });
7.3 includes
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = {2, 4};
bool includes = std::includes(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());
7.3 set_union, set_intersection, set_difference, set_symmetric_difference
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));
result.clear();
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
result.clear();
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
result.clear();
std::set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));
8、常见问题
sort 与 stable_sort 的区别?
sort 采用快速排序(实际是 introsort 算法),不稳定(相等元素的相对位置可能改变),平均时间复杂度 O(n log n)。
stable_sort 采用归并排序,稳定(相等元素相对位置不变),时间复杂度 O(n log n),但空间开销略大。
- 为什么
remove 算法需要配合 erase 使用?
remove 算法的原理是'覆盖'要删除的元素,将保留的元素移到前面,返回新的逻辑尾迭代器,但不修改容器的实际大小。erase 则通过迭代器范围真正删除元素,修改容器大小。因此需结合使用:container.erase(remove(...), container.end())。
- 哪些算法需要容器是已排序的?
二分查找系列(binary_search、lower_bound、upper_bound)、集合算法(set_intersection、set_union 等)、merge 等,这些算法依赖有序性实现高效操作(如二分查找 O(log n))。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,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
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online