std::adjacent_difference 不修改原数组,但若输入输出迭代器重叠(如 v.begin() 同作输入起点和输出起点),会导致数据覆盖;其输出首项为原序列首元素,后续为相邻差,共 n 项,纯差分段需跳过首项或调整迭代器范围。

std::adjacent_difference 会修改原数组吗?
不会。它只读取输入范围的元素,把结果写入目标迭代器指向的位置,原容器内容保持不变。但要注意:如果目标迭代器和输入迭代器指向同一容器(比如用 begin() 作为输出起点),就会覆盖原数据——这不是函数设计的问题,而是你传了重叠的迭代器区间。
常见错误现象:std::adjacent_difference(v.begin(), v.end(), v.begin()) 看似省空间,实则让 v[1] 变成 v[1] - v[0],后续计算全错。
- 安全做法:输出到独立容器,或至少确保输出起始位置不与输入重叠(例如输出到
v.begin() + 1,并预留首元素) - 首元素默认直接复制:输出序列第一个值恒等于输入序列第一个值,不是“差”,这点容易误解
- 若只需差分值(不要首项),记得跳过结果容器的第一个元素
怎么用 std::adjacent_difference 计算真正的「差分数组」(即 a[i] - a[i-1])?
标准行为就是计算相邻差:对输入序列 a[0], a[1], a[2], ..., a[n-1],输出为 a[0], a[1]-a[0], a[2]-a[1], ..., a[n-1]-a[n-2]。所以它天然符合差分数组定义,只是多了一个首项。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 分配大小为
n的结果容器(如std::vector<int> diff(n)),调用后取diff.begin() + 1到diff.end()即是纯差分段 - 若想一步到位只存
n-1个差值,输出到大小为n-1的容器,并把输入范围设为begin()+1到end(),同时用自定义二元操作符:std::adjacent_difference(v.begin()+1, v.end(), diff.begin(), std::minus<>{}) - 注意:
std::minus<>{}是 C++14 起支持的透明函数对象,比写std::minus<int>()更泛化
遇到浮点数或自定义类型时要注意什么?
函数本身不限制类型,只要满足:输入迭代器解引用得到的类型支持 - 运算符,且能赋值给输出迭代器指向的类型。但实际中容易踩坑:
- 浮点数精度丢失不可逆,连续差分再累加还原时误差会放大,别指望
adjacent_difference+partial_sum完全无损往返 - 自定义类型必须重载
operator-,返回类型需能隐式转换或匹配输出容器的 value_type;否则编译失败,错误信息类似:no match for 'operator-' - 若差分结果需要不同类型(如
int输入 →long long差分),不能靠自动推导,得显式指定输出迭代器类型或用中间transform,adjacent_difference不支持输出类型转换
性能和边界情况:空容器或单元素怎么办?
标准规定:对空范围,函数不执行任何操作;对单元素范围,只复制该元素到输出位置,不计算任何差。这很合理,但容易被忽略。
- 空容器输入 → 输出迭代器不动,不写入任何值(不会崩溃,但你要确保输出空间足够或根本没分配)
- 单元素容器 → 输出恰好一个值,就是那个元素本身;此时若你预期“差分数组长度 = 原长 - 1”,就得手动处理边界:长度 ≤ 1 时直接返回空结果
- 没有额外内存分配开销:它只是遍历一次、做 N−1 次减法、N 次赋值,时间复杂度 O(n),空间 O(1)(不含输出存储)
输出容器的大小、首项语义、迭代器重叠、类型运算符约束——这些点漏掉任何一个,都可能让差分结果悄无声息地出错。


















