C++拾取——使用stl标准库生成等差、等比数列的方法
代码是思想的表达。阅读代码是一个猜测、求证的过程。这个过程非常费脑,所以人们都不喜欢啰啰嗦嗦的表达方式。于是在相同认知水平下,简洁高效的表达是喜闻乐见的。本文将抛砖引玉,通过一些案例讲解如何去简化代码。(转载请指明出于breaksoftware的csdn博客)
关系数列
等差数列
比如我们要构建的序列存储的值是0,1,2,3,4……9999。
常规写法
使用for循环
std::vector<int> vec;
for (int i = 0; i < 10000; i++) {vec.push_back(i);
}
简洁写法
iota
使用std标准库的iota。
std::vector<int> vec(10);
std::iota(vec.begin(), vec.end(), 0);
generate
使用std标准库的generate
std::vector<int> vec(10);std::generate(vec.begin(), vec.end(), [] {static int i = 0; return i++;});
或者
std::vector<int> vec(10);std::generate(vec.begin(), vec.end(), [n = 0]() mutable {return n++;});
partial_sum
使用std标准库的partial_sum,代码量减少了一半。 partial是局部、区间的意思,sum是累加的意思。第1、2个参数是需要被计算的容器起止迭代器,第3个参数是计算结果保存的起始迭代器。它还有第4个参数,用于描述怎么计算的。
std::vector<int> vec(10000, 1);
vec[0] = 0;
std::partial_sum(vec.begin(), vec.end(), vec.begin());
std::partial_sum方法对区间数据进行累加。具体的计算规则是
template< class InputIt, class OutputIt >
OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first );
// *(d_first) = *first;
// *(d_first+1) = *first + *(first+1);
// *(d_first+2) = *first + *(first+1) + *(first+2);
// *(d_first+3) = *first + *(first+1) + *(first+2) + *(first+3);
// ...
上述方法有个缺点,就是需要填充10000个1之后再计算。我们可以稍微修改如下,效率会好些。
std::vector<int> vec(10000);
vec[0] = 0;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), [](const int&a, int b) {return a + 1;});
如果要生成9999,9998……0这样递减的数列,则可以把第一个元素赋值为9999后,传递一个减法lambda表达式
std::vector<int> vec(10000);
vec[0] = 9999;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), [](const int& a, int b) {return a - 1;} );
等比数列
比如我们要生成1,2,4,8,16……这样2倍关系的数列。
常规写法
std::vector<int> vec;
for (int i = 0; i < 10; i++) {vec.push_back(pow(2, i));
}
精简写法
generate
std::vector<int> vec(10);std::generate(vec.begin(), vec.end(), [] {static int i = 0; return pow(2, i++);});
或者
std::vector<int> vec(10);std::generate(vec.begin(), vec.end(), [n = 0]() mutable {return pow(2, n++);});
partial_sum
std::vector<int> vec(10, 2);
vec[0] = 1;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), std::multiplies<int>());
使用比值2初始化vector容器,然后给partial_sum传递乘法函数对象。
或者使用lambda表达式
std::vector<int> vec(10);
vec[0] = 1;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), [](const int& x, int y) {return x * 2;});
如果要生成512,256……2,1这样的等比数列,则可以把容器的第一个元素设置为1024,然后给partial_sum传递除法函数对象。
std::vector<int> vec(10, 2);
vec[0] = 512;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), std::divides<int>());
或者使用lambda表达式
std::vector<int> vec(10);
vec[0] = 512;
std::partial_sum(vec.begin(), vec.end(), vec.begin(), [](const int& x, int y) {return x / 2;});
斐波那契数列
常规写法
std::vector<int> vec(10);
vec[0] = 1;
for (auto it = std::next(vec.begin()); it != vec.end(); it++) {auto it_prev = std::prev(it);if (vec.begin() != it_prev) {*it = *it_prev + *std::prev(it_prev);}else {*it = *it_prev;}
}
精简写法
std::vector<int> vec(10);
vec[0] = 1;
std::adjacent_difference(vec.begin(), std::prev(vec.end()), std::next(vec.begin()), std::plus<int>());
adjacent_difference用于计算前后两个数据的差。第4个参数的默认操作是减法,其计算规则如下
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >
ForwardIt2 adjacent_difference( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first );
// *(d_first) = *first;
// *(d_first+1) = *(first+1) - *(first);
// *(d_first+2) = *(first+2) - *(first+1);
// *(d_first+3) = *(first+3) - *(first+2);
// ...
累计型操作
比较常见的累计型操作如累加、累乘
累加
常规写法
std::vector<int> vec = { 16, 8, 4 };
int sum = 0;
for (int n : vec) {sum += n;
}
精简写法
std::vector<int> vec = { 16, 8, 4 };
int sum = std::accumulate(vec.begin(), vec.end(), 0);
代码也减少一半。
accumulate第1、2个参数是需要计算的容器的起止迭代器,第3个参数是初始计算的值。它还有第4个参数,用于描述如何累计。默认是累加操作。
我们再看个累乘操作。
std::vector<int> vec = { 16, 8, 4 };
int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
组合成一个字符串
常规写法
std::vector<int> vec = { 16, 8, 4 };
std::string str;
for (int n : vec) {if (!str.empty()) {str.append(",");}str.append(std::to_string(n));
}
精简写法
std::string s = std::accumulate(std::next(vec.begin()), vec.end(),std::to_string(vec[0]), // start with first element[](std::string a, int b) { return a + ',' + std::to_string(b);}
);
序列比较
两个序列中,相同偏移的元素值相等的个数
常规写法
std::vector<int> a = { 1, 2, 3, 4, 5 };
std::vector<int> b = { 5, 4, 3, 2, 1 };
int num = 0;
auto it_a = a.begin();
auto it_b = b.begin();
for (; it_a != a.end() && it_b != b.end(); it_a++, it_b++) {if (*it_a == *it_b) {num++;}
}
精简写法
std::vector<int> a = { 1, 2, 3, 4, 5 };
std::vector<int> b = { 5, 4, 3, 2, 1 };
int num = std::inner_product(a.begin(), a.end(), b.begin(), 0, std::plus<>(), std::equal_to<>());
inner_product方法对两个序列中相同位置的元素使用第5个参数指向的函数对象计算,计算的结果通过第4个参数指向的函数对象进行再计算。即
template<class InputIt1, class InputIt2, class T,class BinaryOperation1, class BinaryOperation2>
T inner_product( InputIt1 first1, InputIt1 last1,InputIt2 first2, T init,BinaryOperation1 op1,BinaryOperation2 op2 );
// 以初值 init 初始化积累器 acc ,然后
// 以表达式 acc = op1(acc, op2(*first1, *first2)) 修改它,再以表达式acc = op1(acc, op2(*(first1+1), *(first2+1))) 修改它,以此类推
两个序列元素是否完全一致(顺序无关)
比如一个序列a是1,2,3;序列b是2,1,3;序列c是1,2,1。则a和b中元素完全一致,只是顺序不一致;而c和a、b中元素不一致。可以想象这个算法不是简简单单就能写出来的。我们直接看精简写法
精简写法
std::vector<int> v1{ 1,1,2,2,5 };
std::vector<int> v2{ 5,1,2,1,2 };
bool permutation = std::is_permutation(v1.begin(), v1.end(), v2.begin(), v2.end());
is_permutation用于判断两个序列是否是同一个序列的不同(或相同)顺序排列。
C++拾取——使用stl标准库生成等差、等比数列的方法相关推荐
- C++拾取——使用stl标准库实现排序算法及评测
今天看了一篇文章,讲各种语言的优势和劣势.其中一个观点:haskell非常适合写算法,因为使用者不用去关心具体的计算机实现,而只要关注于操作语义.这让它在专心研究算法的人中非常受欢迎.所以很多时候,语 ...
- C++ - STL标准库
1.C++ STL标准库简介 长久以来,软件界一直希望建立一种可重复利用的东西,以及一种得以制造出"可重复运用的东西" 的方法,从函数(functions),类别(classes) ...
- STL标准库及泛型编程
1-认识headers.版本.重要资源 C++ Standard Library Standard Template Library 标准库 > STL 标准库以header files形式呈现 ...
- 侯捷C++课程笔记03: STL标准库与泛型编程
本笔记根据侯捷老师的课程整理而来:STL标准库与泛型编程 pdf版本笔记的下载地址: 笔记03_STL标准库与泛型编程,排版更美观一点(访问密码:3834) 侯捷C++课程笔记03: STL标准库与泛 ...
- STL标准库-容器-set与map
STL标准库-容器-set与multiset C++的set https://www.cnblogs.com/LearningTheLoad/p/7456024.html STL标准库-容器-map和 ...
- C++的STL标准库学习(queue)队列(第四篇)
queue容器基本概念 Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue容器允许从一端新增元素,从另一端移除元素. 也就是说输入的数据要 ...
- C++的STL标准库学习(stack)栈
stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,形式如图所示.stack容器允许新增元素,移除元素,取得栈顶元素,但是除了最顶端外,没有任何其他方法 ...
- C++STL标准库学习笔记(一)sort
目录 前言: 正文 一.排序(sort) 用法1:对基本类型的数组(int,double,char...)从小到大排序 用法2:对元素类型为T的基本类型数组从大到小排序: 用法3:用自定义的排序规则, ...
- C++STL标准库学习总结/索引/学习建议
前言: 如果刚刚开始学习STL标准库,不知道从哪里入手学习的话,建议去中国大学mooc平台,先学习北京大学郭炜老师的<程序设计与算法(一)C语言程序设计>(https://www.icou ...
最新文章
- 中端存储趋势:x86、SSD缓存和虚拟化
- [Nginx] Nginx 配置location总结
- 乘法运算-快速傅里叶变换
- 蓝桥杯省内模拟赛解题过程
- 还没搭建过Vue3.x项目?几行代码搞定~
- mongodb dsl_具有Java DSL的Spring Integration MongoDB适配器
- iOS内存区域部分内容
- java 大数实现_Java中的大数类简单实现
- 一文了解sun.misc.Unsafe
- 如何在Mac上批量转换和调整图像大小
- 六、Linux企业级YUM软件管理
- 微信小程序双层图片swiper滑动(底部图片模糊处理)实现
- 结巴分词5--关键词抽取
- 基于无线通信的多点温湿度采集系统设计
- Java爬取彼岸桌面壁纸的实现(使用Jsoup)
- uniapp获取当前经纬度 地图 支持搜索
- Typora 镜像下载/主题下载
- TomCat 启动报:validateJarFile jar not loaded. See Servlet Spec 2.3, section 9.7.2.
- 【Iriun Webcam】
- cinder(cinderella怎么读英语)
热门文章
- 一起来了解React的四种优秀甘特图方案(下篇)
- LabVIEW图像灰度测量(基础篇—7)
- 力扣(LeetCode)刷题,简单+中等题(第35期)
- 力扣(LeetCode)刷题,简单题(第22期)
- 优达学城《DeepLearning》2-1:卷积神经网络
- C语言实现bmp图像几何变换(移动,旋转,镜像,转置,缩放)
- Unity导出apk出现的问题,JDK,Android SDK,NDK,无“安装模块”
- ROS Melodic安装、配置和使用turtlebot2(集成众多源代码直接下载)
- 在CentOS 6.9 x86_64上开启nginx 1.12.2的stub_status模块(ngx_http_stub_status_module)监控
- 网络增强现实开发简介 Introduction to Web AR development