突破编程_C++_STL教程(数值算法(1))

1 STL 的数值算法概述

STL 的数值算法提供了一系列用于处理数值计算的模板函数。这些算法主要针对容器中的元素进行数学运算和统计计算,使得程序员能够高效地处理数值数据。

STL 数值算法包括了一系列功能丰富的函数,例如 std::accumulate 用于计算容器中元素的累积值,可以方便地进行求和、求积或其他自定义的累积操作。std::inner_product 用于计算两个序列的点积(内积),这在向量运算中尤为常见。std::partial_sum 则用于计算容器中元素的部分和序列,有助于分析序列的局部特性。

此外,std::adjacent_difference 可以计算容器中每对相邻元素的差,这在分析序列的变化趋势时非常有用。而 std::iota 则可以将一系列连续的值填充到容器中,用于生成序列或初始化容器。

这些数值算法的设计目标是提供一种高效、可靠且易用的工具,以支持各种常见的数值计算任务。它们可以与 STL 中的容器(如 vector、list 等)紧密结合,通过迭代器方便地访问容器中的元素。同时,STL 数值算法的底层实现经过优化,确保了高效的运行性能。

2 std::accumulate

std::accumulate 用于计算给定范围内元素的累积值。这个算法特别适用于数值计算,但也可以通过提供自定义的二元操作来执行更复杂的累积任务。

2.1 基本用法

std::accumulate 的基本用法是计算一个序列中所有元素的和。它接受三个参数:范围的起始迭代器、范围的结束迭代器和一个初始值。

基本语法如下:

template<class InputIt, class T>  
T accumulate(InputIt first, InputIt last, T init);
  • first 和 last 是定义输入序列范围的迭代器。
  • init 是累积运算的初始值。
  • 默认的操作是加法,所以如果没有提供自定义操作,std::accumulate 会将序列中的所有元素加起来,并返回总和。

如下为使用示例:

#include <numeric>  
#include <vector>  
#include <iostream>  int main() {std::vector<int> numbers = { 1, 2, 3, 4, 5 };int sum = std::accumulate(numbers.begin(), numbers.end(), 0);std::cout << "Sum of the numbers: " << sum << std::endl;   return 0;
}

上面代码的输出为

Sum of the numbers: 15

在这个例子中,std::accumulate 计算了向量 numbers 中所有元素的总和。

2.2 自定义操作

除了默认的加法操作,std::accumulate 还允许你提供一个自定义的二元操作。这个操作应该接受两个参数,并返回它们的某种累积结果。这使得 std::accumulate 可以用于执行更复杂的任务,比如计算乘积、最大值、最小值等。

带有自定义操作的 std::accumulate 的语法如下:

template<class InputIt, class T, class BinaryOperation>  
T accumulate(InputIt first, InputIt last, T init, BinaryOperation op);
  • op 是一个二元操作函数或函数对象,它定义了如何进行累积。

如下为计算乘积的使用示例:

#include <numeric>  
#include <vector>  
#include <iostream>  
#include <functional>  int main() {std::vector<int> numbers = { 1, 2, 3, 4, 5 };int product = std::accumulate(numbers.begin(), numbers.end(), 1, std::multiplies<int>());std::cout << "Product of the numbers: " << product << std::endl; return 0;
}

上面代码的输出为

Product of the numbers: 120

2.3 自定义数据结构

std::accumulate 不仅可以用于基本数据类型的序列,也可以用于自定义数据结构的序列。通过提供自定义的二元操作,std::accumulate 可以对自定义数据结构的对象执行复杂的累积操作。

自定义数据结构

首先,假设有一个自定义的数据结构,比如一个表示点的类 Point,它包含 x 和 y 两个坐标:

class Point {  
public:  int x, y;  Point(int x = 0, int y = 0) : x(x), y(y) {}  // 可以添加其他成员函数,比如用于输出、比较等  
};

自定义二元操作

对于上面的自定义数据结构,std::accumulate 无法直接使用默认的加法操作进行累积。因此,需要提供一个自定义的二元操作,告诉 std::accumulate 如何合并两个 Point 对象。

假设想要计算一系列点的 x 坐标的总和和 y 坐标的总和,可以定义一个二元操作函数或函数对象来实现这一点:

struct PointAccumulator {  Point operator()(const Point& a, const Point& b) const {  return Point(a.x + b.x, a.y + b.y);  }  
};

这里,PointAccumulator 是一个函数对象,它重载了调用运算符 operator() 来接受两个 Point 对象,并返回一个新的 Point 对象,其中 x 和 y 坐标分别是输入点对应坐标的和。

使用 std::accumulate

现在,可以使用 std::accumulate 和自定义的二元操作来计算一系列 Point 对象的累积和:

#include <iostream>  
#include <vector>  
#include <numeric>  // 自定义数据结构  
class Point {  
public:  int x, y;  Point(int x = 0, int y = 0) : x(x), y(y) {}  // 输出点  void print() const {  std::cout << "(" << x << ", " << y << ")" << std::endl;  }  
};  // 自定义二元操作  
struct PointAccumulator {  Point operator()(const Point& a, const Point& b) const {  return Point(a.x + b.x, a.y + b.y);  }  
};  int main() {  // 创建包含点的向量  std::vector<Point> points = {  Point(1, 2),  Point(3, 4),  Point(5, 6)  };  // 使用 std::accumulate 和自定义二元操作计算累积和  Point sum = std::accumulate(points.begin(), points.end(), Point(), PointAccumulator());  // 输出结果  sum.print(); // 输出: (9, 12)  return 0;  
}

上面代码的输出为

(9, 12)

这个例子创建了一个包含三个 Point 对象的 std::vector。然后,使用 std::accumulate 来计算这些点的累积和。代码中给 std::accumulate 函数传递了向量的起始和结束迭代器,一个初始的 Point 对象(这里是一个默认构造的 Point),以及的自定义二元操作 PointAccumulator 的一个实例。随后 std::accumulate 遍历向量中的每个点,并使用 PointAccumulator 来合并它们,最终得到一个表示所有点坐标和的 Point 对象。

注意事项

  • 自定义二元操作必须能够处理你的数据结构,并返回正确的累积结果。
  • 初始值对于 std::accumulate 的结果很重要。对于自定义数据结构,需要提供一个合适的初始值。在这个例子中,使用了 Point 的默认构造函数来创建一个初始点。
  • 如果自定义的数据结构包含非数值类型的成员(比如字符串或自定义对象),则需要确保二元操作能够适当地处理这些成员。

通过自定义二元操作,std::accumulate 可以适应各种复杂的累积需求,包括处理自定义数据结构的序列。这使得它成为一个非常强大且灵活的算法工具。

3 std::inner_product

std::inner_product 用于计算两个序列的点积(也称为内积)。点积是一个数学概念,常用于向量运算中,其结果是一个标量,表示两个向量的相似度或夹角。在 C++ 中,std::inner_product 可以应用于任何支持基本算术运算的类型,包括但不限于整数、浮点数以及自定义类型。

3.1 基本用法

std::inner_product 的基本语法如下:

template<class InputIt1, class InputIt2, class T>  
T inner_product(InputIt1 first1, InputIt1 last1,  InputIt2 first2, T init);

基本用法中,std::inner_product 会将两个序列中对应位置的元素相乘,并将所有乘积相加,最后返回总和。默认操作是乘法和加法。

#include <iostream>  
#include <vector>  
#include <numeric>  int main() {std::vector<int> v1 = { 1, 2, 3 };std::vector<int> v2 = { 4, 5, 6 };int result = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);std::cout << "Inner product: " << result << std::endl; return 0;
}

上面代码的输出为

Inner product: 32

上面示例中 std::inner_product 计算的是 1*4 + 2*5 + 3*6 的结果。

3.2 自定义操作

std::inner_product 允许为序列元素的合并和乘积的累加提供自定义的二元操作,其语法如下:

template<class InputIt1, class InputIt2, class T, class BinaryOperation1, class BinaryOperation2>  
T inner_product(InputIt1 first1, InputIt1 last1,  InputIt2 first2, T init,  BinaryOperation1 binary_op1,  BinaryOperation2 binary_op2);
  • first1, last1:定义第一个输入序列范围的迭代器。
  • first2:指向第二个输入序列起始位置的迭代器。
  • init:累积运算的初始值。
  • binary_op1:一个二元操作,用于合并第一个序列中的元素。默认为加法。
  • binary_op2:一个二元操作,用于合并两个序列中对应位置的元素。默认为乘法。

可以通过以下方式提供自定义操作:

  • 使用函数对象(functor)或 lambda 表达式:

可以定义一个函数对象(一个带有 operator() 的类)或使用 C++11 引入的 lambda 表达式。

  • 使用标准库中的函数对象:

C++ 标准库提供了一些函数对象,如 std::plus<>, std::minus<>, std::multiplies<> 等,可以直接使用它们作为自定义操作。

  • 使用函数指针:

如果函数符合二元操作的签名(即接受两个参数并返回一个结果),也可以使用函数指针作为自定义操作。

使用自定义操作的示例

假设有两个整数向量,需要计算它们的“点差积”,即对应元素的差的平方和,而不是通常的点积。

#include <iostream>  
#include <vector>  
#include <numeric>  
#include <functional> // for std::plus<> and std::minus<>  // 自定义的二元操作:计算平方  
struct Square {int operator()(int x) const {return x * x;}
};int main() {std::vector<int> v1 = { 1, 2, 3 };std::vector<int> v2 = { 4, 5, 6 };// 使用自定义操作计算点差积  int result = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0,std::plus<>(), // 默认的加法用于累加结果  [](int a, int b) { return (a - b) * (a - b); }); // lambda 表达式计算差的平方  std::cout << "Point difference product: " << result << std::endl; // 输出点差积的结果  return 0;
}

上面代码的输出为

Point difference product: 27

这个例子使用了 std::plus<> 作为 binary_op1 来累加结果,但使用了 lambda 表达式作为 binary_op2 来计算两个对应元素的差的平方。这样,std::inner_product 就会计算 (1-4)^2 + (2-5)^2 + (3-6)^2 的结果。

使用标准库中的函数对象的示例

如果不想定义新的函数对象或 lambda 表达式,也可以直接使用标准库提供的函数对象。例如,使用 std::minus<> 和 std::multiplies<> 来计算两个序列对应元素之差的乘积和:

#include <iostream>  
#include <vector>  
#include <numeric>  
#include <functional> // for std::plus<>, std::minus<> and std::multiplies<>  int main() {std::vector<int> v1 = { 1, 2, 3 };std::vector<int> v2 = { 4, 5, 6 };// 使用标准库函数对象计算对应元素之差的乘积和  int result = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0,std::plus<>(), // 默认的加法用于累加结果  std::multiplies<>()); // 默认的乘法用于计算对应元素的乘积   std::cout << "Sum of differences product: " << result << std::endl; // 输出对应元素之差的乘积和的结果  return 0;
}

上面代码的输出为

Sum of differences product: 32

这个例子使用了 std::plus<> 作为 binary_op1 来累加结果,但使用了 std::multiplies<> 作为 binary_op2 来计算两个对应元素的乘积。这样,std::inner_product 就会计算 (1*4) + (2*5) + (3*6) 的结果。

3.3 自定义数据结构

std::inner_product 是一个通用的算法,它并不直接依赖于特定的数据结构。它接收两个迭代器范围(通常是容器的开始和结束迭代器)以及两个二元操作函数对象或函数指针。因此,开发者可以使用 std::inner_product 来计算任何可迭代的数据结构中元素的某种累积操作,只要提供正确的迭代器和合适的自定义操作。

然而,对于更复杂的数据结构(比如自定义类),可能需要定义合适的操作来匹配 std::inner_product 的期望。这通常意味着需要定义如何合并两个对象(binary_op1)以及如何计算两个对象之间的某种关系(binary_op2)。

下面是一个例子,展示了如何为自定义的数据结构使用 std::inner_product:

#include <iostream>  
#include <vector>  
#include <numeric>  
#include <functional> // for std::plus<>  // 自定义的数据结构  
struct Point {double x, y;// 假设我们想要计算两个点的内积  Point operator*(const Point& other) const {return { x * other.x, y * other.y };}// 假设我们想要累加点的某个属性,比如 x 坐标的和  Point operator+(const Point& other) const {return { x + other.x, y + other.y };}
};int main() {std::vector<Point> points = { {1, 2}, {3, 4}, {5, 6} };// 初始化一个用于累加的点,这里我们初始化为 {0, 0}  Point initial_sum = { 0, 0 };// 使用 std::inner_product 计算所有点的内积和  // 这里我们不需要自定义 binary_op1,因为 Point 类型已经定义了 + 操作符  // 但我们需要自定义 binary_op2 来计算两个点的内积  Point result = std::inner_product(points.begin(), points.end(), points.begin(), initial_sum,std::plus<>(),[](const Point& a, const Point& b) { return a * b; });std::cout << "Sum of inner products: (" << result.x << ", " << result.y << ")" << std::endl;return 0;
}

上面代码的输出为

Sum of inner products: (35, 56)

在这个例子中,Point 结构体定义了两个操作符:operator* 用于计算两个点的内积,operator+ 用于累加点的坐标。当调用 std::inner_product 时,这里传递了 std::plus<> 作为 binary_op1,它将用于累加点的坐标。同时,这里也提供了一个 lambda 表达式作为 binary_op2,它使用 operator* 来计算两个点的内积。

注意:这里的 binary_op1 和 binary_op2 的参数和返回类型需要与迭代器所指向的数据类型(在这里是 Point)兼容。binary_op1 应该接受两个 Point 对象并返回一个 Point 对象,而 binary_op2 应该接受两个 Point 对象并返回一个可以用于累加的值(在这里是一个 double 类型的内积)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/783397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

原型、原型链

原型、原型链 一、原型的作用&#xff1a;&#xff08;两条&#xff09; ​ 1、节省内存空间 ​ 2、实现数据共享&#xff08;继承&#xff09; 二、原型、构造函数、实例对象三者关系&#xff1a; ​ 结论1、任何一个函数都有prototype属性&#xff0c;本身是一个对象 ​…

android WMS服务

android WMS服务 WMS的定义 窗口的分类 WMS的启动 WindowManager Activity、Window、DecorView、ViewRootImpl 之间的关系 WindowToken WMS的定义 WMS是WindowManagerService的简称&#xff0c;它是android系统的核心服务之一&#xff0c;它在android的显示功能中扮演着…

python安装删除以及pip的使用

目录 你无法想象新手到底会在什么地方出问题——十二个小时的血泪之言&#xff01; 问题引入 python modify setup 隐藏文件夹 环境变量的配置 彻底删除python 其他零碎发现 管理员终端 删不掉的windous应用商店apps 发现问题 总结 你无法想象新手到底会在什么地方…

StructStreaming Batch mode和Continuous mode

StructStreaming Batch mode和Continuous mode 让我们把目光集中到 Structured Streaming&#xff0c;也就是流处理引擎本身。Structured Streaming 与 Spark MLlib 并列&#xff0c;是 Spark 重要的子框架之一。值得一提的是&#xff0c;Structured Streaming 天然能够享受 S…

MySql的下载与安装

window系统&#xff1a; 下载MySQL 8.0 访问MySQL官方网站&#xff1a; 打开浏览器&#xff0c;输入网址 https://dev.mysql.com/downloads/mysql/ 进入MySQL下载页面。 选择版本&#xff1a; 在网页中找到“MySQL Community Server”部分&#xff0c;这通常是最新的社区版&am…

JWFD流程图转换为矩阵数据库的过程说明

在最开始设计流程图的时候&#xff0c;请务必先把开始节点和结束节点画到流程图上面&#xff0c;就是设计器面板的最开始两个按钮&#xff0c;先画开始点和结束点&#xff0c;再画中间的流程&#xff0c;然后保存&#xff0c;这样提交到矩阵数据库就不会出任何问题&#xff0c;…

本地搭建多人协作ONLYOFFICE文档服务器并结合Cpolar内网穿透实现公网访问远程办公

文章目录 1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 本篇文章讲解如何使用Docker在本地服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问。 Community Edition允许您在本地服务器上安装ONLYOFFICE文档&…

数仓-hive DDL (带你手敲秒懂hive三种常见分区)

hive 数仓DDL 分区 分区是将表的数据以分区字段的值作为目录去存储 ---> 减少磁盘IO&#xff0c; 方便数据管理 静态分区 创建外表同时指定静态分区字段 create table if not exists table_name(id int,name string)partitioned by (day string,h string); …

python angr库二进制分析和逆向工程

angr 是一个 Python 库&#xff0c;主要用于进行二进制分析和逆向工程。它允许研究人员自动化地探索和分析二进制文件&#xff08;如可执行文件、库等&#xff09;&#xff0c;并提供了一系列工具和组件来解析、模拟和检查二进制代码。 angr 最初是由 UC Santa Barbara 的 She…

【Vue】搭建第一个vue3+vite前段项目

不要奇怪我为啥突然开始写前端的文章&#xff0c;唉&#xff0c;一切都是公司的任务罢了。 其实这周学习了前端和coverity&#xff0c;但是后者就算学了我也不能写在我博客里&#xff0c;所以还是写一写前端吧。 node.js 和 npm npm是一个类似于 maven 的包管理器。 去以下…

Excel数据分子-----------VLOOKUP函数

选择区域的时候一定要把查询条件所处的列放在第一列。 跨表使用 一定要在括号外边摁回车键。 通配符查找 列后面跟上**&“*”** 近似查找 数值格式问题 HLOOP函数 这个是在行中进行搜索 indexmatch实现匹配查找 先利用match查找出在哪一行&#xff0c;再利用index定…

ssm007亚盛汽车配件销售业绩管理统+jsp

亚盛汽车配件销售业绩管理系统设计与实现 摘 要 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让亚盛汽车配件销售信息的管理模式进行升级&#xff0c;也为了更好的维护亚盛汽车配件销售信息&am…

【Java八股学习】Redis持久化 思维导图

说明 文章内容通过学习小林Coding内的优质文章后整理而来&#xff0c;整理成思维导图的方式是为了帮助自己理解、记忆和复习。如若侵权请联系删除&#xff0c;再次对小林Coding内的优质文章表示感谢。参考文章如下&#xff1a; AOF 持久化是怎么实现的&#xff1f;RDB 快照是…

Vue源码---虚拟Dom

Vue源码—虚拟Dom 真实dom 浏览器引擎渲染工作流程大致分为5步&#xff0c;创建dom树 -> 创建style Rules -> 创建render树 -> 布局layout -> 绘制painting 虚拟dom 虚拟dom节点&#xff0c;通过js的object 对象模拟dom中的节点&#xff0c;然后通过特定的rend…

seldom 实战技巧

seldom 是我一直在维护的自动化测试框架。目前GitHub已经 500 star。 最近在项目中使用Seldom poium 编写自动化测试用例。接下来&#xff0c;我就分享一些使用技巧。 如何参数化测试用例 网站的首页&#xff0c;如上面的导航。于是&#xff0c;开始利用poium编写元素定位。…

Leetcode 3098. Find the Sum of Subsequence Powers

Leetcode 3098. Find the Sum of Subsequence Powers 1. 解题思路2. 代码实现 题目链接&#xff1a;3098. Find the Sum of Subsequence Powers 1. 解题思路 这一题思路上的话还是比较直接的&#xff0c;由于我们只需要求出每一个可能的power值&#xff0c;然后求出对应的po…

GitHub常用命令

GitHub常用命令 远程仓库相关命令拉取项目到本地拉取远程仓库推送远程仓库 分支操作相关命令查看所有本地分支查看所有远程分支查看所有本地分支和远程分支切换分支创建本地分支创建远程分支(本地分支push到远程)创建新分支并切换到新分支合并指定分支到当前分支删除分支 代码提…

基于 FFmpeg 和 SDL 的音视频同步播放器

基于 FFmpeg 和 SDL 的音视频同步播放器 基于 FFmpeg 和 SDL 的音视频同步播放器前置知识音视频同步简介复习DTS、PTS和时间基 程序框架主线程解复用线程音频解码播放线程视频解码播放线程 音视频同步逻辑源程序结果工程文件下载参考链接 基于 FFmpeg 和 SDL 的音视频同步播放器…

蓝桥杯备考随手记: Math 类中常用方法

Java的Math类是一个包含数学操作方法的实用工具类。它提供了许多用于执行各种数学计算的静态方法。 下面是Math类中一些常用的方法&#xff1a; abs()&#xff1a;返回参数的绝对值。 int absoluteValue Math.abs(-10); System.out.println(absoluteValue); // Output: 10 c…

EtherCAT主站SOEM -- 25 -- STM32F767-SOEM通过 PV模式(速度模式)控制一个电机转圈圈

EtherCAT主站SOEM -- 25 -- STM32F767-SOEM通过 PV模式(速度模式)控制一个电机转圈圈 0 QT-SOEM视频预览及源代码下载:0.1 QT-SOEM视频预览0.2 QT-SOEM源代码下载0.3 STM32F7-SOEM视频预览0.4 STM32F7-SOEM源代码下载1 程序文件修改替换1.1 allvalue.h1.2 allvalue.c1.3 mot…