C++adjacent_find查找相邻重复

2026-04-11 13:30:27 1025阅读 0评论

adjacent_find:C++里那个专治“连体婴”的小能手

你有没有写过这样的代码:遍历一个 vector<int>,想找出第一对相等的相邻元素?手写循环、加索引、比 v[i] == v[i+1]……写完还担心越界,调试时发现漏了 i < size()-1,又得改。其实,C++ 标准库早给你备好了工具——std::adjacent_find,它不炫技,不绕弯,就干一件事:在一段连续内存里,找第一对紧挨着且满足条件的元素

很多人以为它只是“找相邻重复”,于是只记住了默认用 == 的版本。但这么理解,等于把瑞士军刀当螺丝刀使——它真正的弹性,在于自定义判断逻辑的能力

先看最常用的场景:找重复值。

#include <algorithm>
#include <vector>
#include <iostream>

std::vector<int> nums = {1, 3, 5, 5, 7, 9};
auto it = std::adjacent_find(nums.begin(), nums.end());
if (it != nums.end()) {
    std::cout << "重复出现在索引 " << (it - nums.begin()) 
              << " 和 " << (it - nums.begin() + 1) << "\n";
}
// 输出:重复出现在索引 2 和 3

注意:adjacent_find 返回的是第一个重复元素的迭代器(即前一个),不是两个迭代器组成的对。这点很关键——它和 std::find 保持了一致的行为习惯,也方便后续操作(比如从该位置开始 erase)。

但现实哪有那么多“相等”?更多时候,你要找的是“差值小于阈值的相邻数”“符号相反的相邻浮点”“字符串长度相差不超过1的相邻项”。这时候,传入自定义谓词才是它的高光时刻

比如,处理传感器采样数据时,常需检测“突变”:

std::vector<double> readings = {23.1, 23.2, 23.15, 41.8, 41.75};
auto it = std::adjacent_find(readings.begin(), readings.end(),
    [](double a, double b) { return std::abs(a - b) > 15.0; });
// 找到 23.15 和 41.8 这一对——跳变超限

这里传入的 lambda 接收两个相邻元素(按顺序),返回 true 表示“找到了”。别写反参数顺序——a 是前一个,b 是后一个,这是标准约定,也是你后续做差分、斜率、状态转换时天然的语义。

再举个容易踩坑的例子:找相邻的正负号变化。

std::vector<int> signs = {-2, -1, 3, 4, -5};
auto it = std::adjacent_find(signs.begin(), signs.end(),
    [](int a, int b) { return (a < 0 && b > 0) || (a > 0 && b < 0); });
// 找到 -1 和 3 —— 符号由负转正

有人会下意识写 a * b < 0,但整数溢出风险(尤其 int 较大时)让它不够稳健。显式判断更安全、更可读——工具的价值,从来不在多快,而在让你少动脑去防错

还有一个实用技巧:adjacent_find 能配合 std::distance 快速定位下标,但如果你用的是 std::array 或原生数组,别忘了 std::begin()/std::end() 的存在,避免手动算指针偏移出错。

顺带一提,它和 std::unique 是好搭档,但分工明确:adjacent_find 只查找,不修改std::unique 则负责搬移去重(需配合 erase 才真正删)。别指望它帮你删数据——它连容器都不认识,只认迭代器区间。

性能上,它是线性扫描,O(n),无额外空间开销。底层就是朴素的两两比较,没黑魔法,所以你完全能预估它的耗时。在嵌入式或实时系统里,这种“可知、可控、可测”的行为,比任何花哨算法都让人安心。

最后提醒一个易忽略的事实:adjacent_find 要求输入范围至少有两个元素。如果传入空容器或单元素容器,它直接返回 last 迭代器(即 end()),不会崩溃,但你得自己检查结果——它不替你做边界假设,只忠实地执行你的指令。这恰恰是 C++ 库设计的克制之美:不越界帮忙,也不偷偷埋雷。

下次当你盯着一段“找相邻特征”的循环发呆时,不妨停一秒,问问自己:这段逻辑,是不是可以用 adjacent_find 三行内干净收尾?它不抢眼,不刷存在感,但每次用对了,都像拧紧一颗恰到好处的螺丝——不声不响,整个结构就稳了。

文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
验证码
评论列表 (暂无评论,1025人围观)

还没有评论,来说两句吧...

目录[+]