std::find_if返回首个满足条件元素的迭代器,需用std::distance转为索引并检查it != end();反向查找用rbegin/rend配合base()减1;排序数据优先用lower_bound/upper_bound。

用 std::find_if 找第一个满足条件的索引
直接调用 std::find_if 配合迭代器算术运算,比手写循环更安全、更符合 C++ 习惯。它返回指向首个匹配元素的迭代器,减去 begin() 就是索引。
常见错误是忽略容器为空或未找到时的边界处理——此时返回的是 end(),直接减会得到无效索引。
- 确保容器非空,或先检查
it != vec.end() - 用
std::distance(vec.begin(), it)比it - vec.begin()更通用(支持非随机访问迭代器,虽然数组/vec 通常没问题) - lambda 捕获要明确:条件里用
[&](const auto& x) { return x > 5; }而不是值捕获,避免拷贝开销
std::vector<int> vec = {1, 3, 7, 7, 9, 2};
auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });
int first_idx = (it != vec.end()) ? std::distance(vec.begin(), it) : -1;
// first_idx == 2
</int>
用 std::find_if 逆向找最后一个满足条件的索引
没有现成的 find_if_last,但用 std::find_if 配合反向迭代器最简洁。注意:反向迭代器的 base() 返回的是对应正向位置的**后一个**迭代器,所以要减 1。
容易踩的坑是误以为 rit.base() 直接给出索引,结果偏移 1 位;或者忘记反向查找时逻辑条件不变(仍是“满足条件”,不是“满足相反条件”)。
- 用
vec.rbegin()和vec.rend()构造反向范围 - 找到后调用
rit.base(),再减vec.begin(),最后减 1 - 同样必须检查
rit != vec.rend(),否则base()行为未定义
auto rit = std::find_if(vec.rbegin(), vec.rend(), [](int x) { return x > 5; });
int last_idx = (rit != vec.rend()) ? (rit.base() - vec.begin() - 1) : -1;
// last_idx == 4(对应值 9)
对已排序数组,用 std::lower_bound / std::upper_bound 更高效
如果数组已升序排列且条件是“≥某值”或“==某值”,用二分查找比线性扫描快得多(O(log n) vs O(n))。但注意:这两个函数只适用于**基于值的比较**,不能任意谓词(比如 “x % 3 == 0” 就不行)。
混淆 lower_bound 和 upper_bound 是高频错误:前者找第一个 ≥ value 的位置,后者找第一个 > value 的位置;要找最后一个 == value,得用 upper_bound - 1,且必须确认该位置确实等于 value。
- 先用
std::lower_bound得到左边界迭代器 - 再用
std::upper_bound得到右边界迭代器 - 只有当左边界 ≠ 右边界时,才存在匹配;最后一个索引 =
upper_bound_it - vec.begin() - 1 - 不满足排序前提时结果不可靠,运行时不会报错,但逻辑全错
std::vector<int> sorted = {1, 3, 7, 7, 7, 9};
auto lb = std::lower_bound(sorted.begin(), sorted.end(), 7);
auto ub = std::upper_bound(sorted.begin(), sorted.end(), 7);
if (lb != ub) {
int first = lb - sorted.begin(); // 2
int last = ub - sorted.begin() - 1; // 4
}
</int>
手写循环时如何避免越界和 off-by-one 错误
尽管 STL 更推荐,但某些嵌入式或性能敏感场景仍需手写。核心原则:索引变量用 size_t 要格外小心——它无符号,减 1 会绕回极大值;用 int 或带符号类型更安全。
另一个典型问题是“从后往前找”时写成 i >= 0,但 size_t i 永远 ≥ 0,导致无限循环或越界读取。
- 统一用
int i = static_cast<int>(vec.size()) - 1</int>做反向索引 - 正向循环用
i ,别用 <code>i (size() 返回 unsigned) - 初始化结果变量为 -1,找不到时不覆盖,避免返回垃圾值
真正麻烦的从来不是“怎么写”,而是“怎么证明边界情况都覆盖了”——尤其是空容器、全匹配、全不匹配这三种 case,建议每个都单测一行。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











