以下对 C++ 标准库中
头文件所提供的数值算法与工具做一次系统、深入的梳理,包括算法功能、示例代码、复杂度分析及实践建议。
中定义了一组对数值序列进行累加、内积、差分、扫描等操作的算法,以及部分辅助工具(如 std::iota
、std::gcd
/std::lcm
等)。std::reduce
、std::inclusive_scan
、std::exclusive_scan
、std::transform_reduce
等新算法。std::accumulate
功能:对区间 [first, last)
内所有元素做累加(或自定义二元操作),并将初值 init
加入计算。
原型
template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init);
template<class InputIt, class T, class BinaryOp>
T accumulate(InputIt first, InputIt last, T init, BinaryOp op);
默认行为:init + *first + *next + …
;自定义时执行 op(op(init, *first), *next)…
。
时间复杂度:O(N)
#include
#include
#include
int main() {
std::vector<int> v{1,2,3,4,5};
// 累加
int sum = std::accumulate(v.begin(), v.end(), 0);
// 计算阶乘之和
int fact_sum = std::accumulate(v.begin(), v.end(), 1, [](int a, int b){ return a * b; });
std::cout << sum << ", " << fact_sum; // 输出 15, 120
}
std::inner_product
功能:计算两序列点积,并加上初值 init
。
原型
template<class InputIt1, class InputIt2, class T>
T inner_product(InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init);
template<class InputIt1, class InputIt2, class T,
class BinaryOp1, class BinaryOp2>
T inner_product(InputIt1 first1, InputIt1 last1,
InputIt2 first2, T init,
BinaryOp1 op_sum, BinaryOp2 op_mul);
默认行为:init + Σ (a[i] * b[i])
时间复杂度:O(N)
#include
#include
#include
int main() {
std::vector<int> a{1,2,3}, b{4,5,6};
int dot = std::inner_product(a.begin(), a.end(), b.begin(), 0);
std::cout << dot; // 输出 32
}
std::partial_sum
功能:对区间进行前缀累加,生成与原区间等长的结果序列。
原型
template<class InputIt, class OutputIt>
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first);
template<class InputIt, class OutputIt, class BinaryOp>
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first, BinaryOp op);
默认行为:输出 [a[0], a[0]+a[1], a[0]+a[1]+a[2], …]
;可用自定义 op
替换 +
。
时间复杂度:O(N)
#include
#include
#include
int main() {
std::vector<int> v{1,2,3,4};
std::vector<int> out(v.size());
std::partial_sum(v.begin(), v.end(), out.begin());
// out = {1,3,6,10}
for (int x : out) std::cout << x << ' ';
}
std::adjacent_difference
功能:计算相邻元素差分,同样生成等长序列。
原型
template<class InputIt, class OutputIt>
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first);
template<class InputIt, class OutputIt, class BinaryOp>
OutputIt adjacent_difference(InputIt first, InputIt last, OutputIt d_first, BinaryOp op);
默认行为:输出 [a[0], a[1]−a[0], a[2]−a[1], …]
;自定义 op
替换减法。
时间复杂度:O(N)
#include
#include
#include
int main() {
std::vector<int> v{1,3,6,10};
std::vector<int> diff(v.size());
std::adjacent_difference(v.begin(), v.end(), diff.begin());
// diff = {1,2,3,4}
for (int x : diff) std::cout << x << ' ';
}
std::iota
功能:按等差序列填充区间。
原型
template<class ForwardIt, class T>
void iota(ForwardIt first, ForwardIt last, T value);
行为:*first = value; *(first+1) = value+1; …
。
时间复杂度:O(N)
#include
#include
#include
int main() {
std::vector<int> v(5);
std::iota(v.begin(), v.end(), 10);
// v = {10,11,12,13,14}
for (int x : v) std::cout << x << ' ';
}
std::gcd
与 std::lcm
(C++17 起)功能:分别计算两个整数的最大公约数和最小公倍数。
原型
template<class M, class N>
constexpr std::common_type_t<M,N> gcd(M m, N n);
template<class M, class N>
constexpr std::common_type_t<M,N> lcm(M m, N n);
复杂度:基于欧几里得算法, O ( log min ( m , n ) ) O(\log \min(m,n)) O(logmin(m,n))。
#include
#include
int main() {
std::cout << std::gcd(48, 18) << ' '; // 输出 6
std::cout << std::lcm(48, 18); // 输出 144
}
从 C++17 起,
中加入更高效且可并行化的算法。
算法 | 功能 |
---|---|
std::reduce |
类似 accumulate ,但可并行优化,无序二元操作要满足交换结合性 |
std::inclusive_scan |
包含当前元素的前缀扫描(即 partial_sum 的并行版) |
std::exclusive_scan |
不包含当前元素的前缀扫描 |
std::transform_reduce |
先对每个元素做一元转换,再并行归约 |
std::transform_scan |
先转换后扫描 |
原型举例
// inclusive_scan
template<class InputIt, class OutputIt, class BinaryOp>
OutputIt inclusive_scan(InputIt first, InputIt last, OutputIt d_first, BinaryOp op);
// reduce
template<class InputIt, class T>
T reduce(InputIt first, InputIt last, T init);
并行执行策略:可传入执行策略(std::execution::seq
、par
、par_unseq
)以启用多线程或向量化。
#include
#include
#include
#include
int main() {
std::vector<int> v(1'000'000, 1);
// 并行归约
long sum = std::reduce(std::execution::par, v.begin(), v.end(), 0L);
std::cout << sum;
}
小序列优先用 accumulate
,大规模数据考虑 reduce
accumulate
简单、易读;reduce
在结合律满足时能获得并行加速。前缀和与差分模式
partial_sum
/inclusive_scan
可快速构建前缀和用于区间查询;adjacent_difference
在信号处理、数值微分等场景非常高效。避免整数溢出
long long
、double
)。选择合适的操作符重载
BinaryOp
时,要保证满足需要的结合性、幂等性等特性,以免并行时结果不确定。利用 iota
快速生成测试数据
std::iota
可快速构造等差、递增序列。通过以上对
中各类数值算法的全面详解,相信你能在科学计算、信号处理、统计分析乃至日常开发中高效地利用标准库功能,写出简洁且高性能的代码。祝学习顺利!