STL-常用算法
概述:
- 算法主要是由头文件
<algorithm
<functional>
<numeric>
组成,他们都是非成员函数 <algorithm>
是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等<numeric>
体积很小,只包括几个在序列上面进行简单数学运算的模板函数<functional>
定义了一些模板类,用以声明函数对象
1 常用遍历算法
for_each
//遍历容器transform
//搬运容器到另一个容器中
1.1 for_each
函数原型:
for_each(iterator begin, iterator end, func);
参数解释:
// 遍历算法 遍历容器元素
// beg开始迭代器
// end结束迭代器
// _func函数或者函数对象
//普通函数
void printInt(int val)
{
cout << val << " ";
}
//仿函数
class print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int>v;
for (int i=0; i<10; i++)
{
v.push_back(i);
}
for_each(v.begin(), v.end(), printInt) //👀 普通函数只需要放函数名
cout << endl;
for_each(v.begin(), v.end(), print02()) //👀 仿函数,需要放函数对象
cout << endl;
}
1.2 transform
搬运容器到另一个容器中
函数原型:
transform(iterator begi, iterator end1, iterator beg2, _func);
参数解释:
// beg1 源容器开始迭代器
// end1 源容器结束迭代器
// beg2 目标容器开始迭代器
// _func 函数或者函数对象
class Transform
{
public:
int operator()(int v)
{
return v;
}
};
void test01()
{
vector<int>v;
for (int i=0; i<10; i++)
{
v.push_back(i);
}
vector<int>vTarget;
vTarget.resize(v.size()); //👀 目标容器,需要提前开辟空间
transform(v.begin(), v.end(), vTarget.begin(), Transform()) //👀 仿函数,需要放函数对象
cout << endl;
}
2 常用查找算法
find
//查找元素find_if
//按条件查找元素adjacent_find
//查找相邻重复元素binary_search
//二分查找法count
//统计元素个数count_if
//按条件统计元素个数
2.1 find
函数原型:
find(iterator begin, iterator end, value);
// 注释:按值查找元素,找到返回指定位置迭代器,找不到则返回结尾迭代器位置
示例:查找自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age
}
// 👀 重载 == 底层find知道如何对比person数据类型
bool operator==(const Person& p)
{
if(this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
Person pp("bbb", 20);
vector<Person>::iterator it = find(v.begin(), v.end(), pp);
if (it==v.end())
{
cout << "没有找到" << endl;
}
else {cout << "找到元素" << endl;}
}
2.2 find_if
函数原型:
find_if(iterator begin, iterator end, _Pred);
// 注释:按值查找元素,找到返回指定位置迭代器,找不到则返回结尾迭代器位置
// _Pred 函数或者谓词(返回bool类型的仿函数)
1、查找内置数据类型
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
vector<int> v;
for (int i=0; i<10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it==v.end())
{
cout << "没有找到" << endl;
}
else
{cout << "找到元素" << endl;}
}
2.3 adjacent_find
查找相邻、重复元素
函数原型:
adjacent_find(iterator begin, iterator end);
// 注释:查找相邻重复元素,找到返回相邻元素的第一个位置迭代器,找不到则返回结尾迭代器位置
2.4 binary_search
函数原型:
bool binary_search(iterator begin, iterator end, value);
// 注释:按值查找元素,找到返回true,找不到则返回false
// 只能使用在有序序列
2.5 count
统计元素个数
函数原型:
count(iterator begin, iterator end, value);
// begin 开始迭代器
// end 结束迭代器
// value 统计的元素
// 返回一个int数据
示例:统计自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
bool operator ==(const Person& p)
{
if (this->m_Age == p.m_Age)
{
return true;
}else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> v;
Person p1("刘备", 35);
Person p2("关羽", 35);
Person p3("张飞", 35);
Person p4("赵云", 30);
Person p5("曹操", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
Person p("诸葛亮", 35)
int num = count(v.begin(), v.end(), p);
cout << "与诸葛亮同岁数的人员个数为:" << num << endl;
}
2.6 cont_if
按条件统计元素个数
函数原型:
count_if(iterator begin, iterator end, _Pred);
// begin 开始迭代器
// end 结束迭代器
// _Perd 谓词
// 返回一个int数据
示例:统计内置数据类型
class Greater20
{
pulic:
bool operator()(int val)
{
return val > 20;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(30);
v.push_back(20);
v.push_back(40);
int num = count_if(v.begin(), v.end(), Greater20());
cout << "大于20的元素个数为:" << num << endl;
}
3 常用排序算法
sort
//对容器内元素进行排序random_shuffle
//洗牌 指定范围内的元素随机调整次序merge
// 容器元素合并,并存储到另一容器中reverse
// 反转指定范围的元素
3.1 sort
函数原型:
sort(iterator begin, iterator end, _Pred);
// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
// _Pred 谓词,不填则默认为升序
示例:
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(50);
v.push_back(40);
// 利用sort进行升序
sort(v.begin(), v.end())
for_each(v.begin(), v.end(), myPrint);
cout << endl;
// 改变为 降序
sort(v.begin(), b.end(), greater<int>());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}
3.2 random_shuffle
函数原型:
random_shuffle(iterator begin, iterator end);
// 指定范围内的元素随机调整次序
3.3 merge
函数原型:
merge(iterator begin1, iterator end1, iterator begin2, iterator end2, iterator dest
// 容器元素合并,并存储到目标容器中
// 注意:两个容器必须是有序的
// dest 目标容器开始迭代器(依旧是有序的)
示例:
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i=0; i<10; i++)
{
v1.push_back(i);
v2.push_back(i+1);
}
vector<int>vTarget;
vTarget.resize(v1.size()+v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
}
3.4 reverse
函数原型:
reverse(iterator begin, iterator end);
// 反转指定范围的元素
4 常用的拷贝和替换算法
copy
//容器内指定范围的元素拷贝到另一容器中replace
//将容器内指定范围旧元素,修改为新元素replace_if
//容器内指定范围满足条件的元素替换为新元素swap
// 互换两个容器的元素
4.1 copy
函数原型:
copy(iterator begin, iterator end, iterator dest);
// dest 目标起始迭代器
4.2 replace
函数原型:
replace(iterator begin, iterator end, oldvalue, newvalue);
// 将区间内旧元素 替换成 新元素
4.3 replace_if
函数原型:
replace_if(iterator begin, iterator end, _Pred, newvalue);
// 将区间内 满足条件的 替换成 新元素
示例:
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
class Greater30
{
public:
bool Greater(int val)
{
return val >= 30;
}
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
cout << "替换前:" << endl;
for_each(v.begin(), v.end(), MyPrint());
//将大于等于30的替换成3000
replace_if(v.begin(), v.end(), Greater30(), 3000);
}
4.4 swap
函数原型:
swap(container c1, container c2);
//互换两个容器的元素
示例:
class MyPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i=0; i<10, i++)
{
v1.push_back(i);
v2.push_back(i+100);
}
cout << "替换前:" << endl;
for_each(v1.begin(), v1.end(), MyPrint());
for_each(v2.begin(), v2.end(), MyPrint());
swap(v1, v2);
}
5 常用算数生成算法
算术生产算法书属于小型算法,使用时包含头文件#include<numeric>
accumulate
//计算容器元素累计总和fill
//向容器中添加元素
5.1 accumulate
函数原型:
accumulate(iterator begin, iterator end, value);
// 计算容器元素累计总和
// value 起始值(相当于一个)
void test01()
{
vector<int> v;
for (int i=0; i<100, i++)
{
v.push_back(i);
}
int total = accumulate(v.begin(), v.end(), 100);
}
5.2 fill
函数原型:
fill(iterator begin, iterator end, value);
// 计算容器元素累计总和
// value 填充的值
void test01()
{
vector<int> v;
v.resize(10);
fill(v.begin(), v.end(), 100);
}
6 常用集合算法
set_intersectoin(iterator begin1, iterator end1, iterator begin2, iterator end2, iterator dest)
// 求两个容器的交集
// 注意:两个集合必须是有序序列
// 得到的目标容器,也是有序序列set_union(iterator begin1, iterator end1, iterator begin2, iterator end2, iterator des)
// 求两个容器的并集
// 注意:两个集合必须是有序序列set_difference(iterator begin1, iterator end1, iterator begin2, iterator end2, iterator des)
//求两个容器的差集
// 注意:两个集合必须是有序序列
// 容器1跟容器2有先后位置,不同的参数位置,结果不一样
---------------------以下为补充内容------------------------
#include < algorithm >头文件
binary_search:
查找某个元素是否出现
a.函数模板:bool binary_search(arr[],arr[]+size , indx)
b.参数说明:
arr[]
: 数组首地址
size
:数组元素个数
indx
:需要查找的值
return
: true/ false
c.函数功能: 在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。
lower_bound(左值查找):
查找第一个大于或等于某个元素的位置。
a.函数模板:
lower_bound(arr[],arr[]+size , indx)
b.参数说明:
arr[]
: 数组首地址
size
:数组元素个数
indx
: 需要查找的值
return
:iterator
c.函数功能:
函数lower_bound()
在first
和last
中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置(注意是地址)。如果所有元素都小于val,则返回last
的位置
d.举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100
.设要插入数字3,9,111
, pos
为要插入的位置的下标,则
/注意因为返回值是一个指针,所以减去数组的指针就是int变量了/
vector<int> number{ 4,10,11,30,69,70,96,100 };
auto it = lower_bound(number.begin(), number.begin() + 8, 3) - number.begin();
// it= 0.
// 即number数组的下标为0的位置。
int arr[8] = { 4,10,11,30,69,70,96,100 };
auto pos = lower_bound( arr, arr+ 8, 9) - number;
// pos = 1,
//即number数组的下标为1的位置(即10所在的位置)。
auto pos = lower_bound( number, number + 8, 111) - number;
// pos = 8,
//即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
e.注意:
函数lower_bound()
在first
和last
中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
upper_bound (右值查找):
查找第一个大于某个元素的位置。
a.函数模板:
upper_bound(arr[],arr[]+size , indx):
b.参数说明:
arr[]
: 数组首地址
size
:数组元素个数
indx
:需要查找的值
return
:地址
c.函数功能:
函数upper_bound()
返回的在前闭后开
区间查找的关键字的上界,返回大于val的第一个元素位置
例如:一个数组number[4] = 1,2,2,4
,upper_bound(2)
后,返回的位置是3(下标)
也就是4所在的位置,同样,如果插入元素大于数组中全部元素,返回的是last。(注意:数组下标越界)
返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置 。
代码二分搜索BS的循环与递归实现
#include <cstdio>
using namespace std;
int a[100]= {4,10,11,30,69,70,96,100};
int binarySearch(int x,int n)
{
int left =0;
int right=n-1;
while(left<=right)
{
int mid =(left+right)/2;
if(x==a[mid])
{
return mid;
}
if(x>a[mid])
{
left=mid+1;
}
else
{
right =mid-1;
}
}
return -1;//未找到x
}
//二分搜索递归实现
int recurisonBinarySearch(int left,int right,int x)
{
if(left>right)
{
return -1;
}
int mid =(left+right)/2;
if(x==a[mid])
{
return mid;
}
if(x>a[mid])
{
return recurisonBinarySearch(mid+1,right,x);
}
else
{
return recurisonBinarySearch(left,mid-1,x);
}
}
int main()
{
int x;
int ans1,ans2;
scanf("%d",&x);
ans1=binarySearch(x,8);
ans2=recurisonBinarySearch(0,7,x);
printf("%d %d\n",ans1,ans2);
return 0;
}
#include < numeric >头文件
accumulate()函数介绍
accumulate()
函数返回数组内元素的累积值。
例如,可以使用accumulate()函数计算vector<int> nums
中所有元素的累加和,通过修改操作符(binary_op)
可以计算累乘积或其他自定义累计结果。
(1).函数定义
template <class InputIterator, class T>
T accumulate (InputIterator first, InputIterator last, T init);
template <class InputIterator, class T, class BinaryOperation>
T accumulate (InputIterator first, InputIterator last, T init,
BinaryOperation binary_op);
first, last
: 容器迭代器,计算范围;
init
: 初始值,默认为1。若初始值init=2,那么accumulate(nums.begin(),nums.end(),2) 返回 2+nums[0]+nums[1]+…+nums[n-1];
binary_op
: 元素间的操作符号,默认为plus(求和)。
(2).用法示例
a. 基本用法,求vector<int> nums
的元素累计和、累计减、累计乘、累计除
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums = { 6,3,2 };
// 默认求和,输出为:0+6+3+2 = 11
cout << accumulate(nums.begin(), nums.end(), 0) << endl;
// 初始值为1求和,输出为:1+6+3+2 = 12
cout << accumulate(nums.begin(), nums.end(), 1) << endl;
// 求累减,输出为:0-6-3-2 = -11
cout << accumulate(nums.begin(), nums.end(), 0, minus<int>()) << endl;
// 求累乘,输出为:1*6*3*2 = 36
cout << accumulate(nums.begin(), nums.end(), 1, multiplies<int>()) << endl;
// 求累除,输出为:36/6/3/2 = 1
cout << accumulate(nums.begin(), nums.end(), 36, divides<int>()) << endl;
return 0;
输出:
11
12
-11
36
b. 自定义操作符binary_op
如1.所示,可以设置二元操作符为plus,minus,multiplies
和divides
对容器内的元素进行加、减、乘和除的accumulate
操作。
同样的,我们可以使用函数指针、函数对象或lambda表达式自定义一个二元运算符对元素进行accumulate操作。
接下来我们定义一个 求和后再模3 的二元运算符 add_mod_3_fun
,即add_mod_3_fun(a,b) = (a+b)%3
,然后使用该二元运算符对nums进行accumulate操作。
代码如下:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int add_mod_3_fun(const int& a, const int& b) {
return (a + b) % 3;
}
class ADD_MOD_3 {
public:
int operator()(const int& a, const int& b) {
return (a + b) % 3;
}
};
int main(int, char**) {
vector<int> nums = { 6,3,2 };
// 使用自定义二元运算符
// 使用函数指针,输出为 (0+6)%3=0 -> (0+3)%3=0 -> (0+2)%3 = 2
cout << accumulate(nums.begin(), nums.end(), 0, add_mod_3_fun) << endl;
// 使用函数对象
cout << accumulate(nums.begin(), nums.end(), 0, ADD_MOD_3()) << endl;
// 使用lambda表达式
cout << accumulate(nums.begin(), nums.end(), 0, [](const int& a, const int& b) {return (a + b) % 3;}) << endl;
return 0;
}
输出:
2
2
2
需要注意的是,在使用函数指针、函数对象或lambda表达式自定义运算符号时,参数列表应该为const int&
类型以保证acumulate()
函数不会对数组内原有元素做任何修改,尽管不为const int&
类型依旧可以正常运行,但是为了安全考虑还是需要尽量使用const int&
。
adjacent_difference()函数介绍
从名字也可以看出adjacent_difference()
是用来计算数组各元素与相邻元素(这里的相邻指的是前一个元素)之间差异的函数。
例如:若nums为待计算数组,result为存放差异结果的数组,那么:
result[0] = nums[0]
result[1] = nums[1] - nums[0]
result[2] = nums[2] - nums[1]
result[3] = nums[3] - nums[2]
result[4] = nums[4] - nums[3]
可以看到,由于数组首个元素没有前一个元素,函数规定数组首个元素与前一个元素的差异为首个元素本身。另外在计算差异时,默认使用-
减法运算,即differenc[i]=nums[i]-nums[i-1]
。
(1).函数定义
template <class InputIterator, class OutputIterator>
OutputIterator adjacent_difference (InputIterator first, InputIterator last,OutputIterator result);
template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator adjacent_difference ( InputIterator first, InputIterator last,OutputIterator result, BinaryOperation binary_op );
first, last
:容器迭代器,计算范围;
result
:迭代器,存储差异结果数组 起始位置;
binary_op
:计算差异的运算符,默认为减法运算;
函数返回值
:迭代器,存储差异结果数组的最后一个差异元素的下一个位置;
(2).用法示例
a. 基本用法,求vector<int>
的各元素与前一个元素的差、和、积和商
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums = { 1,2,3,5,9,11,12 };
cout << "nums:";
for (int i = 0; i < nums.size(); i++) {
cout << nums[i] << " ";
}
cout << endl;
vector<int> results(nums.size());
// 计算各元素与前一个元素的 差
cout << "minus:";
vector<int>::iterator iter = adjacent_difference(nums.begin(), nums.end(), results.begin());
for (int i = 0; i < results.size();i++) {
cout << results[i] << " ";
}
cout << endl;
// 计算各元素与前一个元素的 和
cout << "plus:";
iter = adjacent_difference(nums.begin(), nums.end(), results.begin(), plus<int>());
for (int i = 0; i < results.size();i++) {
cout << results[i] << " ";
}
cout << endl;
// 计算各元素与前一个元素的 乘
cout << "multiplies:";
iter = adjacent_difference(nums.begin(), nums.end(), results.begin(), multiplies<int>());
for (int i = 0; i < results.size();i++) {
cout << results[i] << " ";
}
cout << endl;
// 计算各元素与前一个元素的 除
cout << "divides:";
iter = adjacent_difference(nums.begin(), nums.end(), results.begin(), divides<int>());
for (int i = 0; i < results.size();i++) {
cout << results[i] << " ";
}
cout << endl;
return 0;
}
结果:
nums:1 2 3 5 9 11 12
minus:1 1 1 2 4 2 1
plus:1 3 5 8 14 20 23
multiplies:1 2 6 15 45 99 132
divides:1 2 1 1 1 1 1
从输出结果中我们可以看出,无论我们使用什么运算符(减、加、乘还是除)计算差异,数组首个元素与前一个元素的差异都为首个元素本身。
b. 自定义操作符binary_op
与accumulate()类似,adjacent_difference()函数中也可以使用函数指针、函数对象或lambda表达式自定义差异运算法则,此处不在赘述。
c. 注意事项
- 在使用数组result存储nums差异结果时,需要保证
result.size()>=nums.size()
; adjacent_difference()
函数的返回值指向的是 最后一个差异结果的下一个元素位置,而不是result数组的最后一个位置。
例如,若nums.size()等于3,result.size()等于5,那么
iter=adjacent_difference(nums.begin(), nums.end(), result.begin());
之后,iter
指向result
的第4个元素位置。
3.inner_product()函数介绍
inner product
直译成中文为内积,的确该函数的功能与向量计算中的内积运算类似,inner_product()
函数可以计算两个数组(向量)的内积结果。
例如:
两个数组分别为nums_1 = {1,2,3},nums_2 = {2,3,4}
。那么两数组的内积
inner_product(nums_1.begin(), nums_1.end(), nums_2.begin(),0);
即为:0 + (1*2)+(2*3)+(3*4) = 20
。
(1).函数定义
template <class InputIterator1, class InputIterator2, class T>
T inner_product (InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, T init);
template <class InputIterator1, class InputIterator2, class T,class BinaryOperation1, class BinaryOperation2>
T inner_product (InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, T init,BinaryOperation1 binary_op1,BinaryOperation2 binary_op2);
first1,last1,first2
:容器迭代器,分别代表第一个数组的起始位置、终止位置和第二个数组的起始位置;
init
:初始值,最后与两数组的内积向加;
binary_op1
:二元运符,内积操作中外部的运算符号,默认为加法运算;
binary_op2
:二元运符,内积操作中内部的运算符号,默认为乘法运算;
(2).用法示例
a. 基本用法,计算两个数组的内积
将数组nums_1,nums_2
视作两个相同维度的向量,inner_product()
函数可以计算这两个向量(数组)的内积。
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums_1 = { 1,2,3 };
vector<int> nums_2 = { 2,4,6 };
// 28 = 0 + (1*2)+(2*4)+(3*6) = 2+8+18 = 28
cout << inner_product(nums_1.begin(), nums_1.end(), nums_2.begin(), 0) << endl;
// 33 = 5 + (1*2)+(2*4)+(3*6) = 2+8+18 = 33
cout << inner_product(nums_1.begin(), nums_1.end(), nums_2.begin(), 5) << endl;
return 0;
}
输出:
28
33
1
2
b. 自定义内积运算法则
默认两个数组的内积运算为:先各个元素相乘(内部运算符,binary_op2
)然后再相加(binary_op1
)。我们可以通过自定义binary_op1
和binary_op2
实现自定义的内积运算。示例如下:
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums_1 = { 1,2,3 };
vector<int> nums_2 = { 2,4,6 };
// 自定义内积操作
// 外部运算依旧为加法,内部运算为 减法
// -5 = 1 + (1-2)+(2-4)+(3-6) = -5
cout << inner_product(nums_1.begin(), nums_1.end(), nums_2.begin(), 1, plus<int>(), minus<int>()) << endl;
// 外部运算依旧为乘法,内部运算为 加法
// 162 = 1*(1+2)*(2+4)*(3+6) = 3*6*9 = 162
cout << inner_product(nums_1.begin(), nums_1.end(), nums_2.begin(), 1, multiplies<int>(), plus<int>()) << endl;
return 0;
}
输出:
-5
162
partial_sum()函数介绍
partial_sum()
函数可以计算数组的部分和,所谓部分和即为数组从首个元素到第i个元素的和。
例如:若nums
为待计算数组,result
为存放部分和的结果数组,那么:
result[0] = nums[0]
result[1] = nums[0] + nums[1]
result[2] = nums[0] + nums[1] + nums[2]
result[3] = nums[0] + nums[1] + nums[2] + nums[3]
result[4] = nums[0] + nums[1] + nums[2] + nums[3] + nums[4]
其实从以上示例中也可以看出,所谓的部分和即为数组的前缀和。
(1).函数定义
template <class InputIterator, class OutputIterator>
OutputIterator partial_sum (InputIterator first, InputIterator last,OutputIterator result);
template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator partial_sum (InputIterator first, InputIterator last,OutputIterator result,BinaryOperation binary_op);
first,last
:容器迭代器,待计算的数组起始、终止位置;
result
:容器迭代器,存放部分和结果数组的起始位置;
binary_op
:二元运算符,计算部分和的运算法则;
返回值
:容器迭代器,结果数组最后一个 部分和元素 的下一个位置;
(2).用法示例
a. 基本用法,计算数组的部分和(前缀和)
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums = { 1,2,3,4,5 };
vector<int> results(nums.size(), 0);
vector<int>::iterator iter = partial_sum(nums.begin(), nums.end(), results.begin());
for (int i = 0; i < results.size(); i++) {
cout << results[i] << " ";
}
cout << endl;
return 0;
}
输出:
1 3 6 10 15
b. 自定义操作符binary_op
与前面accumulate(), adjacent_difference()
函数类似,可以使用函数指针
,函数对象
与lambda
表达式自定义求部分和的运算符号,此处不在赘述。
需要注意的是:结果容器results和原数组nums内的元素必须相同。
例如:假如nums
内元素为pair<int, int>
类型,我们需要计算nums[i].second
的前缀和,那么results
数组内的元素也必须为pair<int, int>
类型,代码如下:
vector<pair<int, int>> nums;
for(int i=0; i<5; i++){
nums.push_back(pair<int, int>(i, 2*i));
}
vector<pair<int, int>> results(nums.size());
partial_sum(nums.begin(), nums.end(), results.begin(), [](const pair<int, int>&a, const pair<int, int>&b){
return pair<int, int>(a.second+b.second, 0);
});
iota()函数介绍
单从函数名字iota()
并不能看出该函数的作用,因为该函数与前面其他函数的命名规则不同,该函数的名字iota
并不是源自英文单词,而是来自希腊字母ι。该函数源于Ken Iverson
发明的编程语言APL
中的ι函数,其作用是生成一个以n为起始元素值,之后每个元素都增1,同时希腊字母ι
也有极小,很小的一部分的意思。
因此,再C++中iota()
函数的作用与APL中的ι函数类似,为使用以指定数值为起始,之后的元素依次增1的序列填充指定数组。
(1).函数定义
template <class ForwardIterator, class T>
void iota (ForwardIterator first, ForwardIterator last, T val);
first,last
:容器迭代器,待填充的数组;
val
:初始元素值;
(2).用法示例
填充数组nums
,令其第一个元素值为0,步长为1的递增数列。
代码:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main(int, char**) {
vector<int> nums(5, 0);
iota(nums.begin(), nums.end(), 0);
for (int i = 0; i < nums.size(); i++) {
cout << nums[i] << " ";
}
return 0;
}
输出:
0 1 2 3 4
(补充)C++17新增的几个实用函数
gcd()函数
gcd()
函数用来计算最大公约数(greatest common divisor
)。
例如:gcd(12,18)
返回6
;
lcm()函数
lcm()
函数用来计算最小公倍数(least common multiple
)。
例如:gcd(12,18)
返回36
;
midpoint()函数
midpoint()
函数用来计算整数、浮点数或指针的中点值。
例如:midpoint(2,5)
返回3
解释:(2+5)/2
取整等于3
。
除了上面这三个函数之外,C++17中还新增了reduce(),transform_reduce(),inclusive_scan()等函数,详细信息读者可以查阅Standard library header 。
参考:
https://blog.csdn.net/Strengthennn/article/details/120789648
https://www.cnblogs.com/wkfvawl/p/9475939.html
https://www.bilibili.com/video/BV1et411b73Z?p=287