名稱空間
變體
操作

std::adjacent_difference

來自 cppreference.com
< cpp‎ | 演算法
 
 
演算法庫
有約束演算法與針對範圍的演算法 (C++20)
有約束的演算法,例如 ranges::copyranges::sort 等……
執行策略 (C++17)
排序及相關操作
劃分操作
排序操作
二分搜尋操作
(於已劃分範圍上)
集合操作(於已排序範圍上)
歸併操作(於已排序範圍上)
堆操作
最小/最大值操作
(C++11)
(C++17)
字典序比較操作
排列操作
C 庫
數值操作
(C++11)
adjacent_difference
  
未初始化記憶體上的操作
 
 
定義於標頭檔案 <numeric>
template< class InputIt, class OutputIt >

OutputIt adjacent_difference( InputIt first, InputIt last,

                              OutputIt d_first );
(1) (C++20 起為 constexpr)
template< class ExecutionPolicy,

          class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
                                ForwardIt1 first, ForwardIt1 last,

                                ForwardIt2 d_first );
(2) (C++17 起)
template< class InputIt, class OutputIt, class BinaryOp >

OutputIt adjacent_difference( InputIt first, InputIt last,

                              OutputIt d_first, BinaryOp op );
(3) (C++20 起為 constexpr)
template< class ExecutionPolicy,

          class ForwardIt1, class ForwardIt2, class BinaryOp >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy,
                                ForwardIt1 first, ForwardIt1 last,

                                ForwardIt2 d_first, BinaryOp op );
(4) (C++17 起)

Tdecltype(first) 的值型別。

1)[firstlast) 為空,則不執行任何操作。
否則,按順序執行以下操作:
  1. 建立一個型別為 T 的累加器 acc,並用 *first 初始化它。
  2. acc 賦值給 *d_first
  3. 對於 [++firstlast) 中的每個迭代器 iter,按順序執行以下操作:
a) 建立一個型別為 T 的物件 val,並用 *iter 初始化它。
b) 計算 val - acc(C++20 前)val - std::move(acc)(C++20 起)
c) 將結果賦值給 *++d_first
d)val 複製(C++20 前)移動(C++20 起) 賦值給 acc
2)[firstlast) 為空,則不執行任何操作。
否則,按順序執行以下操作:
  1. *first 賦值給 *d_first
  2. 對於 [1std::distance(first, last)) 中的每個整數 i,按順序執行以下操作:
a) 計算 curr - prev,其中 currfirst 的第 i 個迭代器,prevfirst 的第 i - 1 個迭代器。
b) 將結果賦值給 *dest,其中 destd_first 的第 i 個迭代器。
3)(1) 相同,但改為計算 op(val, acc)(C++20 前)op(val, std::move(acc))(C++20 起)
4)(2) 相同,但改為計算 op(curr, prev)

給定 binary_op 作為實際的二元操作,

  • 如果滿足以下任何條件,程式將不正確:
  • 對於過載 (1,3)
  • T 不能從 *first 構造。
  • acc 不能寫入 d_first
  • binary_op(val, acc)(C++20 前)binary_op(val, std::move(acc))(C++20 起) 的結果不能寫入 d_first
  • 對於過載 (2,4)
  • *first 不能寫入 d_first
  • binary_op(*first, *first) 的結果不能寫入 d_first
  • 給定 d_last 為要 返回 的迭代器,若滿足以下任一條件,則行為未定義:
(C++20 起)
  • 對於過載 (2,4)[firstlast)[d_firstd_last) 重疊。
  • binary_op 修改了 [firstlast)[d_firstd_last) 的任何元素。
  • binary_op 使 [firstlast][d_firstd_last] 中的任何迭代器或子範圍失效。

目錄

[編輯] 引數

first, last - 定義要操作的元素 範圍 的迭代器對
d_first - 目標範圍的開頭
policy - 要使用的 執行策略
op - 將應用的二元操作函式物件。

函式的簽名應等效於以下內容

 Ret fun(const Type1 &a, const Type2 &b);

簽名不需要有 const &
型別  Type1 Type2 必須是 iterator_traits<InputIt>::value_type 型別物件可隱式轉換為它們的型別。型別 Ret 必須是 OutputIt 型別物件可解引用並賦值 Ret 型別值的型別。​

型別要求
-
InputIt 必須滿足 LegacyInputIterator 的要求。
-
OutputIt 必須滿足 LegacyOutputIterator 的要求。
-
ForwardIt1, ForwardIt2 必須滿足 LegacyForwardIterator 的要求。

[編輯] 返回值

指向所寫入的最後一個元素之後的迭代器,若 [firstlast) 為空則為 d_first

[編輯] 複雜度

給定 Nstd::distance(first, last)

1,2) 精確執行 N-1operator-
3,4) 精確執行 N-1 次二元函式 op

[編輯] 異常

帶有模板引數 ExecutionPolicy 的過載按如下方式報告錯誤

  • 若作為演算法一部分呼叫的函式執行丟擲異常且 ExecutionPolicy標準策略 之一,則呼叫 std::terminate。對於任何其他 ExecutionPolicy,行為是實現定義的。
  • 如果演算法未能分配記憶體,則丟擲 std::bad_alloc

[編輯] 可能的實現

adjacent_difference (1)
template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first)
{
    if (first == last)
        return d_first;
 
    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;
    *d_first = acc;
 
    while (++first != last)
    {
        value_t val = *first;
        *++d_first = val - std::move(acc); // std::move since C++20
        acc = std::move(val);
    }
 
    return ++d_first;
}
adjacent_difference (3)
template<class InputIt, class OutputIt, class BinaryOp>
constexpr // since C++20
OutputIt adjacent_difference(InputIt first, InputIt last, 
                             OutputIt d_first, BinaryOp op)
{
    if (first == last)
        return d_first;
 
    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;
    *d_first = acc;
 
    while (++first != last)
    {
        value_t val = *first;
        *++d_first = op(val, std::move(acc)); // std::move since C++20
        acc = std::move(val);
    }
 
    return ++d_first;
}

[編輯] 注意

引入 acc 是因為 LWG issue 539 的決議。使用 acc 而非直接計算差值的原因是,若以下型別不匹配,後者的語義會令人困惑:

  • InputIt 的值型別
  • OutputIt 的可寫型別
  • operator-op 的引數型別
  • operator-op 的返回型別

acc 用作快取迭代元素值的中間物件

  • 其型別是 InputIt 的值型別
  • 寫入 d_first 的值(即 operator-op 的返回值)會賦值給它
  • 其值會傳遞給 operator-op
char i_array[4] = {100, 100, 100, 100};
int  o_array[4];
 
// OK: performs conversions when needed
// 1. creates “acc” of type char (the value type)
// 2. “acc” is assigned to the first element of “o_array”
// 3. the char arguments are used for long multiplication (char -> long)
// 4. the long product is assigned to the output range (long -> int)
// 5. the next value of “i_array” is assigned to “acc”
// 6. go back to step 3 to process the remaining elements in the input range
std::adjacent_difference(i_array, i_array + 4, o_array, std::multiplies<long>{});

[編輯] 示例

#include <array>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
 
void println(auto comment, const auto& sequence)
{
    std::cout << comment;
    for (const auto& n : sequence)
        std::cout << n << ' ';
    std::cout << '\n';
};
 
int main()
{
    // Default implementation - the difference between two adjacent items
    std::vector v{4, 6, 9, 13, 18, 19, 19, 15, 10};
    println("Initially, v = ", v);
    std::adjacent_difference(v.begin(), v.end(), v.begin());
    println("Modified v = ", v);
 
    // Fibonacci
    std::array<int, 10> a {1};
    std::adjacent_difference(std::begin(a), std::prev(std::end(a)),
                             std::next(std::begin(a)), std::plus<>{});
    println("Fibonacci, a = ", a);
}

輸出

Initially, v = 4 6 9 13 18 19 19 15 10 
Modified v = 4 2 3 4 5 1 0 -4 -5 
Fibonacci, a = 1 1 2 3 5 8 13 21 34 55

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
LWG 242 C++98 op 不得有副作用 它不能修改
涉及的範圍
LWG 539 C++98 結果所需型別要求
評估和賦值缺失
已新增
LWG 3058 C++17 對於過載 (2,4),每次呼叫
operator-op 的結果都會賦值給一個臨時
物件,然後該物件再賦值給輸出範圍
直接將結果賦值
給輸出
範圍

[編輯] 參閱

計算一個範圍元素的部分和
(函式模板) [編輯]
對一個範圍的元素進行求和或摺疊
(函式模板) [編輯]