剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)
一、移除性算法 (remove)
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// TEMPLATE FUNCTION remove_copy
template < class _InIt, class _OutIt, class _Ty > inline _OutIt _Remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty &_Val, _Range_checked_iterator_tag) { // copy omitting each matching _Val _DEBUG_RANGE(_First, _Last); _DEBUG_POINTER(_Dest); for (; _First != _Last; ++_First) if (!(*_First == _Val)) *_Dest++ = *_First; return (_Dest); } template < class _InIt, // TEMPLATE FUNCTION remove |
如下图所示:
假设现在想要remove 的元素是3,则传入到
接着遍历First ~ Last 区间的元素,将非移除元素拷贝到前面,覆盖前面的元素,最后的指向如图,函数返回的是Dest 位置,如下代
码所示:
for (; _First != _Last; ++_First)
if (!(*_First == _Val))
*_Dest++ = *_First;
由上图可看出移除性算法并没有改变元素的个数,如果要真正删除,可以将remove 的返回值传入erase 进行删除,如:
v.erase(remove(v.begin(), v.end(), 3), v.end()); 即会将后面两个元素4 和 5 删除掉。
在这里顺便提一下,erase 会使当前迭代器失效,但可以返回下一个迭代器,故如果需要在遍历中删除,下面的做法才是正确的:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <iostream>
#include <vector> using namespace std; int main(void) //for (vector<int>::iterator it=v.begin(); it!=v.end(); ++it) for (vector<int>::iterator it = v.begin(); it != v.end();) cout << endl; |
示例代码1:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element(int n) int main(void) for_each(v.begin(), v.end(), print_element); /*remove(v.begin(), v.end(), 3); v.erase(remove(v.begin(), v.end(), 3), v.end()); return 0; |
二、变序性算法( rotate)
|
1
2 3 4 5 6 7 |
template<class _FwdIt> inline
void rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last) { // rotate [_First, _Last) if (_First != _Mid && _Mid != _Last) _Rotate(_CHECKED_BASE(_First), _CHECKED_BASE(_Mid), _CHECKED_BASE(_Last), _Iter_cat(_First)); } |
rotate 调用了_Rotate,实际上_Rotate 继续调用了某个函数,内部实现代码比较长,而且不容易看懂,这边可以看一下简易的等价
版本实现,来自这里,如下:
|
1
2 3 4 5 6 7 8 9 10 11 12 |
template <class ForwardIterator>
void rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last) { ForwardIterator next = middle; while (first != next) { swap (*first++, *next++); if (next == last) next = middle; else if (first == middle) middle = next; } } |
假设一个容器有 1 2 3 4 5 6 六个元素,现在想把 1 2 放到后面去,可以这样写 rotate(v.begin(), v.begin()+2, v.end()); 如下图所示:
即将first 与 next 对应的元素互换且不断向前推进,直到first == next 为止。
三、排序算法 (sort)
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
template<class _RanIt> inline
void sort(_RanIt _First, _RanIt _Last) { // order [_First, _Last), using operator< _DEBUG_RANGE(_First, _Last); std::_Sort(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Last - _First); } template < class _RanIt, |
sort 重载了两个版本,第一个版本只有2个参数,默认按从小到大排序(using operator<);第二个版本有三个参数,即可以自定义比较逻辑
(_Pred)。它们都调用了标准库的std::_Sort, 跟踪进去发现比较复杂,在_Sort 内会根据一些条件选择不同的排序方式,如标准库的堆排序,合并
排序,插入排序等等。站在使用的角度看,没必要去深究,但如果是想学习相关的排序,那是很好的资源。
示例代码2:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element(int n) bool my_greater(int a, int b) int main(void) for_each(v.begin(), v.end(), print_element); rotate(v.begin(), v.begin() + 2, v.end()); sort(v.begin(), v.end()); sort(v.begin(), v.end(), my_greater); return 0; |
此外,sort 有个坑,如果你自己传递比较逻辑,需要注意,如下:
四、已序区间算法 (lower_bound 、upper_bound)
使用这些算法的前提是区间已经是有序的。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// TEMPLATE FUNCTION lower_bound
template < class _FwdIt, class _Ty, class _Diff > inline _FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty &_Val, _Diff *) { // find first element not before _Val, using operator< _DEBUG_ORDER_SINGLE(_First, _Last, true); _Diff _Count = 0; _Distance(_First, _Last, _Count); for (; 0 < _Count; ) if (_DEBUG_LT(*_Mid, _Val)) template < class _FwdIt, |
lower_bound() 返回第一个“大于等于给定值" 的元素位置,其实还重载了另一个low_bound 版本,如下:
|
1
2 3 4 5 6 7 |
// TEMPLATE FUNCTION lower_bound WITH PRED
template < class _FwdIt, class _Ty, class _Diff, class _Pr > inline _FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty &_Val, _Pr _Pred, _Diff *) |
也就是可以自定义比较逻辑,需要注意的是如果使用这个版本,那么区间应该本来就是按comp 方法排序的,如下面这句话:
The elements are compared using operator< for the first version, and comp for
the second. The elements in the range shall already
be sorted according
to this same criterion (operator< or comp),
or at least partitioned with
respect to val.
由于是已序区间,所以函数内用的是二分查找,而两个版本主要的代码不同在于:
_DEBUG_LT(*_Mid, _Val)
_DEBUG_LT_PRED(_Pred, *_Mid, _Val)
upper_bound 与 lower_bound 类似,不过返回的是第一个”大于给定值“ 的元素位置。
示例代码3:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element(int n) int main(void) for_each(v.begin(), v.end(), print_element); vector<int>::iterator it; it = upper_bound(v.begin(), v.end(), 10); return 0; |
五、数值算法(accumulate)
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// TEMPLATE FUNCTION accumulate
template < class _InIt, class _Ty > inline _Ty _Accumulate(_InIt _First, _InIt _Last, _Ty _Val) { // return sum of _Val and all in [_First, _Last) _DEBUG_RANGE(_First, _Last); for (; _First != _Last; ++_First) _Val = _Val + *_First; return (_Val); } template < class _InIt, // TEMPLATE FUNCTION accumulate WITH BINOP template < class _InIt, |
accumulate 重载了两个版本,第一个版本实现的是累加,第二个版本带_Func 参数,可以自定义计算,比如累乘等。代码都比较好理解,就不赘述
了。看下面的示例代码4:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> #include <numeric> using namespace std; void print_element(int n) int mult(int a, int b) int main(void) for_each(v.begin(), v.end(), print_element); // 累加 // 累乘 return 0; |
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)的更多相关文章
- 从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)
一.移除性算法 (remove) C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ...
- 背景建模技术(二):BgsLibrary的框架、背景建模的37种算法性能分析、背景建模技术的挑战
背景建模技术(二):BgsLibrary的框架.背景建模的37种算法性能分析.背景建模技术的挑战 1.基于MFC的BgsLibrary软件下载 下载地址:http://download.csdn.ne ...
- 变动性算法源代码分析与使用示例(copy_backward、 transform、 replace_copy_if 等)
首先回顾前面的文章,我们把for_each 归类为非变动性算法,实际上它也可以算是变动性算法,取决于传入的第三个参数,即函数 指针.如果在函数内对容器元素做了修改,那么就属于变动性算法. 变动性算法源 ...
- 非变动性算法源代码分析与使用示例( for_each、min_element 、find_if、search 等)
非变动性算法代码分析与示例: 一.for_each C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // TEMPLATE FUNCTION for_eac ...
- Https与Http,SSL,DevOps, 静态代码分析工具,RFID, SSH, 非对称加密算法(使用最广泛的一种是RSA), 数字签名, 数字证书
在URL前加https://前缀表明是用SSL加密的. 你的电脑与服务器之间收发的信息传输将更加安全. Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定. http和h ...
- HashMap的结构算法及代码分析
HashMap算是日常开发中最长用的类之一了,我们应该了解它的结构跟算法: 参考文章: http://blog.csdn.net/vking_wang/article/details/14166593 ...
- 圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单
圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单 //// CircleCore.h// Quartz//// Created by 仙人掌 on 12 ...
- KMP算法以及优化(代码分析以及求解next数组和nextval数组)
KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...
- 编程算法 - 圆圈中最后剩下的数字(递推公式) 代码(C++)
圆圈中最后剩下的数字(递推公式) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 0,1...,n-1这n个数字排成一个圆圈, 从数字0開始 ...
随机推荐
- 【转】2012年7月12 – 腾讯公司 WEB高级应用开发工程师 最新面试题
腾讯面试(WEB高级应用开发工程师<PHP>)非答案啊!!! 开始正题之前,容博主啰嗦两句吧,呵呵.(你也可跳过直接到红色字体看题!) 腾讯一直是我很敬重的企业,尽管小企鹅在战略上饱受争议 ...
- Wix使用整理(一)
由于工作需要,学习了一段时间Wix,总算小有起色.鉴于国内Wix 的普及和使用有限,这里将个人遇到得问题和解决方案记录下来,以便交流和相互促进. Wix :全称 Windows Installer ...
- Emacs复制粘贴乱码问题以及修改当前文件编码
编码修改: 为了和Linux兼容,win环境下将emacs编码修改为utf-8,随意复制了其他关于emacs编码的配置,如下: (setq locale-coding-system 'utf-8) ( ...
- React的第一个例子
准备: 官网:https://facebook.github.io/react/downloads.html Github地址:https://github.com/facebook/react 首先 ...
- JS中实现字符串和数组的相互转化
早上起来看了一道js的面试题,是这样描述的:利用var s1=prompt("请输入任意的字符串","")可以获取用户输入 的字符串,试编程将用户输入的字符串“ ...
- Spark Streaming中空batches处理的两种方法(转)
原文链接:Spark Streaming中空batches处理的两种方法 Spark Streaming是近实时(near real time)的小批处理系统.对给定的时间间隔(interval),S ...
- .NET 代码注入 CodeInject
CInject (or CodeInject) 允许直接往托管的代码中注入代码,而无需反编译.可在单个或者多个方法中注入你要执行的代码.使用 CInject 时你无需了解目标应用的细节,你通过注入来轻 ...
- 【架构】OpenResty相关资料
OpenResty最佳实践 在2012年的时候,我加入到奇虎360公司,为新的产品做技术选型.由于之前一直混迹在python圈子里面,也接触过nginx c模块的高性能开发,一直想找到一个兼备pyth ...
- linux查看当前shell的方法
这篇文章主要对比一下 source 命令执行shell文件和 ./ping.sh 这种方式执行shell文件的区别. 1. source ping.sh 这个是在当前的shell 中执行 ping ...
- DevExpressComponents-14.2.5 破解过程,正在编写,未完
首先,批评一下cnblogs,在win10的环境下,需要加入到兼容视图列表方可正常编辑内容, 声明,本人在14.2.3 的源代码环境下,编译未通过,相关功能报错,索性选择破解,在此,只是学习测试使用, ...