C++17 中的 std::reduce:详细教程

文章目录

    • [1. 简介](#1. 简介)
    • [2. 函数签名](#2. 函数签名)
    • [3. 使用场景](#3. 使用场景)
      • [3.1 简单的累加操作](#3.1 简单的累加操作)
      • [3.2 自定义归并操作](#3.2 自定义归并操作)
      • [3.3 并行计算的性能优势](#3.3 并行计算的性能优势)
    • [4. 注意事项](#4. 注意事项)
      • [4.1 归并操作的结合律和交换律](#4.1 归并操作的结合律和交换律)
      • [4.2 默认值的使用](#4.2 默认值的使用)
    • [5. 总结](#5. 总结)

1. 简介

std::reduce 是 C++17 标准库中引入的一个算法,用于对范围内的元素进行归并操作。它类似于 std::accumulate,但在某些情况下提供了更灵活的处理方式,尤其是在并行计算方面。

2. 函数签名

std::reduce 的基本函数签名如下:

cpp 复制代码
template<class InputIt>
typename std::iterator_traits<InputIt>::value_type
reduce(InputIt first, InputIt last);

template<class InputIt, class T>
T reduce(InputIt first, InputIt last, T init);

template<class InputIt, class T, class BinaryOperation>
T reduce(InputIt first, InputIt last, T init, BinaryOperation binary_op);

template<class ExecutionPolicy, class ForwardIt>
typename std::iterator_traits<ForwardIt>::value_type
reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last);

template<class ExecutionPolicy, class ForwardIt, class T>
T reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init);

template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOperation>
T reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init, BinaryOperation binary_op);
  • InputIt/ForwardIt:迭代器类型,表示要归并的范围。
  • T:归并操作的初始值类型。
  • BinaryOperation:用于归并的二元操作函数。
  • ExecutionPolicy:执行策略,可以是 std::execution::seq(顺序执行)、std::execution::par(并行执行)或 std::execution::unseq(无序执行)。

3. 使用场景

3.1 简单的累加操作

以下是一个简单的累加示例:

cpp 复制代码
#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    int sum = std::reduce(nums.begin(), nums.end());
    std::cout << "Sum: " << sum << std::endl; // 输出 15
    return 0;
}

这里,std::reduce 默认使用加法操作。

3.2 自定义归并操作

可以通过传递自定义的二元操作函数来实现不同的归并逻辑。例如,计算数组中元素的最大值:

cpp 复制代码
#include <iostream>
#include <vector>
#include <numeric>
#include <execution>

int main() {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    int maxElement = std::reduce(std::execution::par, nums.begin(), nums.end(), nums[0], [](int a, int b) {
        return std::max(a, b);
    });
    std::cout << "Maximum element: " << maxElement << std::endl; // 输出 5
    return 0;
}

这里,我们使用了 std::execution::par 来启用并行执行。

3.3 并行计算的性能优势

std::reduce 支持并行执行策略,这使得它在处理大规模数据时能够显著提高性能。例如,计算一个大数组的和:

cpp 复制代码
#include <iostream>
#include <vector>
#include <numeric>
#include <execution>
#include <chrono>

int main() {
    std::vector<int> nums(10000000, 1); // 一个包含 1000 万个元素的数组
    auto start = std::chrono::high_resolution_clock::now();
    int sum = std::reduce(std::execution::par, nums.begin(), nums.end());
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Sum: " << sum << ", Time taken: " << duration << " ms" << std::endl;
    return 0;
}

通过使用 std::execution::par,std::reduce 可以利用多核处理器进行并行计算。

4. 注意事项

4.1 归并操作的结合律和交换律

std::reduce 的归并操作要求是结合律(Associative)和交换律(Commutative)的。如果归并操作不满足这些性质,结果可能是不确定的。例如,减法操作不满足结合律和交换律,因此在并行执行时可能会导致不同的结果:

cpp 复制代码
std::vector<int> nums = {32, 16, 8, 4, 2, 1};
int result1 = std::reduce(nums.begin() + 1, nums.end(), nums[0], std::minus<>{});
int result2 = std::reduce(std::execution::par, nums.begin() + 1, nums.end(), nums[0], std::minus<>{});
std::cout << result1 << ", " << result2 << std::endl; // 输出可能不同

4.2 默认值的使用

std::reduce 的默认值是元素类型的默认构造值。如果默认值不是归并操作的单位元(Identity Element),可能会导致意外的结果。例如,对于整数类型,加法的单位元是 0,乘法的单位元是 1。

5. 总结

std::reduce 是一个强大且灵活的算法,适用于各种归并操作,尤其是需要并行处理的场景。它与 std::accumulate 类似,但在并行执行方面提供了更好的支持。通过合理使用 std::reduce,可以简化代码并提高性能。

希望这篇教程对你有所帮助!如果有任何问题,欢迎随时提问。

相关推荐
我命由我123451 分钟前
Jetpack Compose - @Preview 注解
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
为美好的生活献上中指5 分钟前
Spring AI Advisor 深度实战:构建严谨的 AI Agent 拦截链
java·人工智能·spring·advisor·aiagent
ruofu338 分钟前
如何让docker使用提前下载好的镜像,而不是在线拉取
java·spring cloud·docker
爱敲键盘的猴子8 分钟前
深入理解 Spring IoC -- 基于 XML 的 Bean 配置详解
xml·java·spring
艾莉丝努力练剑15 分钟前
【Qt:问题解决】Qt程序入口点错误修复:MinGW ABI兼容问题
java·服务器·开发语言·qt·文件系统·动静态库
程序员黑豆7 小时前
Java 注释详解:单行、多行与文档注释的完整指南
java·前端·ai编程
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧8 小时前
C++学习:基础知识的掌握
c++·visualstudio
wuyk5558 小时前
第2章:六步换相原理全解+STM32工程实战
c语言·开发语言·stm32·单片机·嵌入式硬件
hey_sml9 小时前
JAVA每日一学---CompletableFuture中thenApply与thenCompose区别详解
java·开发语言
Doraemomo9 小时前
数据结构-环形链表
java·数据结构·链表