什么是非变动算法?
非变动算法(Non-modifying Sequence Operations)是指不会直接修改容器元素值的算法。它们通常用于查找、计数、比较、遍历等操作,保证原始数据不被更改,适合读操作场景。
常见非变动算法包括:
for_eachfindfind_iffind_if_notcountcount_ifall_ofany_ofnone_ofmismatchequalsearchadjacent_find
2 非变动算法详解
2.1 for_each
原理:
对区间内每个元素执行指定操作(通常是函数或 Lambda),不会修改元素值。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
void PrintElement(int x) {
std::cout << x << " ";
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 对每个元素执行 PrintElement
std::for_each(vec.begin(), vec.end(), PrintElement);
std::cout << std::endl;
return 0;
}
适用场景:
遍历容器并执行只读操作(如打印、统计)。
对比传统方法:
传统 for 循环也能实现,但 for_each 更简洁、可读性更强,且可结合函数对象或 Lambda 使用。
2.2 find
原理:
在区间内查找第一个等于指定值的元素,返回迭代器。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {10, 20, 30, 40};
auto it = std::find(vec.begin(), vec.end(), 30);
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl;
} else {
std::cout << "Not found" << std::endl;
}
return 0;
}
适用场景:
查找具体值是否存在。
对比传统方法:
手写 for 循环查找,代码冗长且易出错;find 简化实现。
2.3 find_if 和 find_if_not
原理:
find_if:查找第一个满足谓词条件的元素。find_if_not:查找第一个不满足谓词条件的元素。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {2, 4, 5, 8};
// 查找第一个奇数
auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x % 2 != 0; });
if (it != vec.end()) {
std::cout << "First odd: " << *it << std::endl;
}
// 查找第一个不是偶数的元素
auto it2 = std::find_if_not(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
if (it2 != vec.end()) {
std::cout << "First not even: " << *it2 << std::endl;
}
return 0;
}
适用场景:
查找满足自定义条件的元素。
对比传统方法:
传统 for 循环需手动写条件判断,find_if 更灵活且易维护。
2.4 count 和 count_if
原理:
count:统计区间内等于指定值的元素个数。count_if:统计区间内满足谓词条件的元素个数。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 2, 3, 4, 2};
// 统计值为2的元素个数
int cnt = std::count(vec.begin(), vec.end(), 2);
std::cout << "Count of 2: " << cnt << std::endl;
// 统计偶数个数
int even_cnt = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; });
std::cout << "Count of even: " << even_cnt << std::endl;
return 0;
}
适用场景:
统计元素出现次数、满足条件的元素数量。
对比传统方法:
手动累加计数,count/count_if更高效、代码更简洁。
2.5 all_of、any_of、none_of
原理:
all_of:区间内所有元素都满足谓词条件。any_of:区间内有任意一个元素满足谓词条件。none_of:区间内没有元素满足谓词条件。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
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; });
std::cout << "All even: " << all_even << std::endl;
std::cout << "Any odd: " << any_odd << std::endl;
std::cout << "None negative: " << none_negative << std::endl;
return 0;
}
适用场景:
快速判断一组元素是否全部/部分/完全不满足某条件。
对比传统方法:
传统 for 循环需手动设置标志变量,易出错;STL算法高效且表达力强。
2.6 mismatch
原理:
比较两个区间,返回第一个不相等的元素对的迭代器。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3, 4};
std::vector<int> b = {1, 2, 0, 4};
auto result = std::mismatch(a.begin(), a.end(), b.begin());
if (result.first != a.end()) {
std::cout << "First mismatch: " << *result.first << " vs " << *result.second << std::endl;
} else {
std::cout << "No mismatch found" << std::endl;
}
return 0;
}
适用场景:
比较两个序列,查找第一个不同的元素。
对比传统方法:
手写 for 循环比较,代码繁琐;mismatch一行代码解决。
2.7 equal
原理:
判断两个区间的元素是否全部相等。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 3};
bool is_equal = std::equal(a.begin(), a.end(), b.begin());
std::cout << "Is equal: " << is_equal << std::endl;
return 0;
}
适用场景:
判断两个序列内容完全一致。
对比传统方法:
手动逐元素比较,equal更简洁高效。
2.8 search
原理:
在区间内查找另一个区间(子序列)首次出现的位置。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 2, 3};
std::vector<int> sub = {2, 3};
auto it = std::search(vec.begin(), vec.end(), sub.begin(), sub.end());
if (it != vec.end()) {
std::cout << "Subsequence found at index: " << std::distance(vec.begin(), it) << std::endl;
} else {
std::cout << "Subsequence not found" << std::endl;
}
return 0;
}
适用场景:
查找子序列在容器中的位置。
对比传统方法:
传统嵌套循环查找子序列,代码复杂;search一行搞定。
2.9 adjacent_find
原理:
查找区间内相邻且满足条件的元素对,返回第一个元素的迭代器。
用法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 2, 3, 4};
// 查找相邻相等的元素
auto it = std::adjacent_find(vec.begin(), vec.end());
if (it != vec.end()) {
std::cout << "First adjacent equal: " << *it << std::endl;
}
return 0;
}
适用场景:
查找重复元素、特殊相邻关系。
对比传统方法:
手写 for 循环,易出错;adjacent_find更安全高效。
3 总结与扩展
3.1 优势
代码简洁:STL算法将常用操作封装,大幅减少重复代码。
安全高效:避免手动迭代错误,性能经过优化。
表达力强:结合 Lambda 表达式,逻辑清晰易懂。
3.2 扩展应用
可与变动算法结合,先用非变动算法筛选、统计,再用变动算法处理数据。
结合自定义谓词,实现复杂条件判断和查找。
3.3 注意事项
非变动算法不会改变容器内容,但 Lambda 或函数体内可间接修改外部数据,要注意副作用。
使用正确的迭代器区间,避免越界。
评论区