从零开始学C++之STL(七):剩下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 < // TEMPLATE FUNCTION remove |
如下图所示:
假设现在想要remove 的元素是3,则传入到 _Remove_copy 函数的3个参数如上图第一行所示,Val 即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 删除掉。
示例代码1:
|
1 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element( int main( for_each(v.begin(), v.end(), print_element); /*remove(v.begin(), v.end(), 3); v.erase(remove(v.begin(), v.end(), return |
二、变序性算法( rotate)
|
1 |
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 |
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 |
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 < |
sort 重载了两个版本,第一个版本只有2个参数,默认按从小到大排序(using operator<);第二个版本有三个参数,即可以自定义比较逻辑
(_Pred)。它们都调用了标准库的std::_Sort, 跟踪进去发现比较复杂,在_Sort 内会根据一些条件选择不同的排序方式,如标准库的堆排序,合并
排序,插入排序等等。站在使用的角度看,没必要去深究,但如果是想学习相关的排序,那是很好的资源。
示例代码2:
|
1 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element( bool my_greater( int main( for_each(v.begin(), v.end(), print_element); rotate(v.begin(), v.begin() + sort(v.begin(), v.end()); sort(v.begin(), v.end(), my_greater); return |
四、已序区间算法 (lower_bound 、upper_bound)
使用这些算法的前提是区间已经是有序的。
|
1 |
// 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 = ; _Distance(_First, _Last, _Count); for (; if (_DEBUG_LT(*_Mid, _Val)) template < |
lower_bound() 返回第一个“大于等于给定值" 的元素位置,其实还重载了另一个low_bound 版本,如下:
|
1 |
// 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 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> using namespace std; void print_element( int main( for_each(v.begin(), v.end(), print_element); vector< it = upper_bound(v.begin(), v.end(), return |
五、数值算法(accumulate)
|
1 |
// 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 < // TEMPLATE FUNCTION accumulate WITH BINOP template < |
accumulate 重载了两个版本,第一个版本实现的是累加,第二个版本带_Func 参数,可以自定义计算,比如累乘等。代码都比较好理解,就不赘述
了。看下面的示例代码4:
|
1 |
#include <iostream>
#include <vector> #include <list> #include <algorithm> #include <numeric> using namespace std; void print_element( int mult( int main( for_each(v.begin(), v.end(), print_element); // 累加 // 累乘 return |
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)的更多相关文章
- 剩下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 ...
- 从零开始学C++之STL(四):算法简介、7种算法分类
一.算法 算法是以函数模板的形式实现的.常用的算法涉及到比较.交换.查找.搜索.复制.修改.移除.反转.排序.合并等等. 算法并非容器类型的成员函数,而是一些全局函数,要与迭代器一起搭配使用. 算法的 ...
- [转贴]从零开始学C++之STL(一):STL六大组件简介
一.STL简介 (一).泛型程序设计 泛型编程(generic programming) 将程序写得尽可能通用 将算法从数据结构中抽象出来,成为通用的 C++的模板为泛型程序设计奠定了关键的基础 (二 ...
- 从零开始学ios开发(七):Delegate,Action Sheet, Alert
Action Sheet和Alert是2种特殊的控件(暂且称之为控件吧,其实不是控件真正的控件,而是ios中的2个类,这2个类定义了2种不同类型的用于和用户交互的弹出框),Action Sheet是从 ...
- [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, cl ...
- [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, ...
- 从零开始学Electron笔记(七)
在之前的文章我们介绍了一下Electron中的对话框 Dialog和消息通知 Notification,接下来我们继续说一下Electron中的系统快捷键及应用打包. 全局快捷键模块就是 global ...
- .net基础学java系列(七)赶鸭子上架看项目代码
项目用到的技术栈 序列化 com.alibaba.fastjson.JSON; https://github.com/alibaba/fastjson/wiki/Quick-Start-CN 日志 l ...
- 《从零开始学Swift》学习笔记(Day 59)——代码排版
原创文章,欢迎转载.转载请注明:关东升的博客 代码排版包括: 空行.空格.断行和缩进等内容.代码排版内容比较多工作量很多,但是非常重要. 空行 空行将逻辑相关的代码段分隔开,以提高可读性.下列情况应该 ...
随机推荐
- Temporary ASP.NET Files 文件夹中保存的是什么内容?[转]
转自:http://www.cnblogs.com/suiqirui19872005/archive/2007/05/14/746320.html ASP.NET 页面请求的处理过程需要使用一些临时文 ...
- 3D图片采集与展示(SurfaceView 自适应 Camera, 录制视频, 抽取帧)
最近在做一个3D图片采集与展示. 主要功能为:自定义Camera(google 已经摈弃了Camera, 推荐使用Camera2,后续篇幅,我将会用Camera2取代Camera),围绕一个物体360 ...
- js中的function
Math方法详解 Math.sqrt(x) 计算X开平方 Math.sqrt(x,y) 计算xy Math.round(x) 计算x 四舍五入的值 getBoundingClientRe ...
- 混入模式(max-in)实现继承
混入模式并不是一种复制完整的对象,而是从多个对象中复制出任意的成员并将这些成员组合成一个新的对象. 实现如下: function mix(){ var arg,prop,child = {}; for ...
- django 学习杂记
django1.9 学习路径 http://python.usyiyi.cn/django/intro/tutorial02.html django 中url路径带参数,在view中应该如何处理 应该 ...
- javascript取消disabled属性
jQuery: $("#ID").attr("disabled",false);
- FTP两种工作模式:主动模式(Active FTP)和被动模式(Passive FTP)
在主动模式下,FTP客户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,然后开放N+1号端口进行监听,并向服务器发出PORT N+1命令.服务器接收到命令后,会用其本地的FTP数据端口 ...
- 深度学习word2vec笔记之应用篇
好不容易学了一个深度学习的算法,大家是否比较爽了?但是回头想想,学这个是为了什么?吹牛皮吗?写论文吗?参加竞赛拿奖吗? 不管哪个原因,都显得有点校园思维了. 站在企业的层面,这样的方式显然是不符合要求 ...
- BZOJ 1001 狼抓兔子
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子 ...
- 最新版AltiumDesignerSummer9下载+破解
下载地址:ed2k://|file|AltiumDesignerSummer9Build9.3.1.19182.7z|1875307483|e65d364bf987fb5dcfb81c081a1562 ...