一、移除性算法 (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
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,
          class _OutIt,
          class _Ty >  inline
_OutIt unchecked_remove_copy(_InIt _First, _InIt _Last,
                             _OutIt _Dest,  const _Ty &_Val)
{
     // copy omitting each matching _Val
     return _STD _Remove_copy(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest, _Val,
                             _STD _Range_checked_iterator_tag());
}

// TEMPLATE FUNCTION remove
template <  class _FwdIt,
          class _Ty >  inline
_FwdIt remove(_FwdIt _First, _FwdIt _Last,  const _Ty &_Val)
{
     // remove each matching _Val
    _First = find(_First, _Last, _Val);
     if (_First == _Last)
         return (_First);     // empty sequence, all done
     else
    {
         // nonempty sequence, worth doing
        _FwdIt _First1 = _First;
         return (_STDEXT unchecked_remove_copy(++_First1, _Last, _First, _Val));
    }
}

如下图所示:

假设现在想要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:

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
28
29
30
 
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

int main( void)
{
     int a[] = {  1,  3,  2,  3,  4,  5 };
    vector< int> v(a, a +  6);

for_each(v.begin(), v.end(), print_element);
    cout << endl;

/*remove(v.begin(), v.end(), 3);
    for_each(v.begin(), v.end(), print_element);
    cout<<endl;*/

v.erase(remove(v.begin(), v.end(),  3), v.end());
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

return  0;
}

二、变序性算法( rotate)

C++ Code 
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 继续调用了某个函数,内部实现代码比较长,而且不容易看懂,这边可以看一下简易的等价

版本实现,来自这里,如下:

C++ Code 
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)

C++ Code 
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,
          class _Pr >  inline
void sort(_RanIt _First, _RanIt _Last, _Pr _Pred)
{
     // order [_First, _Last), using _Pred
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pred);
    std::_Sort(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Last - _First, _Pred);
}

sort 重载了两个版本,第一个版本只有2个参数,默认按从小到大排序(using operator<);第二个版本有三个参数,即可以自定义比较逻辑

(_Pred)。它们都调用了标准库的std::_Sort, 跟踪进去发现比较复杂,在_Sort 内会根据一些条件选择不同的排序方式,如标准库的堆排序,合并

排序,插入排序等等。站在使用的角度看,没必要去深究,但如果是想学习相关的排序,那是很好的资源。

示例代码2:

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
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)
{
    cout << n <<  ' ';
}

bool my_greater( int a,  int b)
{
     return a > b;
}

int main( void)
{
     int a[] = {  1,  2,  3,  4,  5,  6 };
    vector< int> v(a, a +  6);

for_each(v.begin(), v.end(), print_element);
    cout << endl;

rotate(v.begin(), v.begin() +  2, v.end());
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

sort(v.begin(), v.end());
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

sort(v.begin(), v.end(), my_greater);
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

return  0;
}

四、已序区间算法 (lower_bound 、upper_bound)

使用这些算法的前提是区间已经是有序的。

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
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; )
    {
         // divide and conquer, find half that contains answer
        _Diff _Count2 = _Count /  2;
        _FwdIt _Mid = _First;
        std::advance(_Mid, _Count2);
        _DEBUG_ORDER_SINGLE(_Mid, _Last,  false);

if (_DEBUG_LT(*_Mid, _Val))
            _First = ++_Mid, _Count -= _Count2 +  1;
         else
            _Count = _Count2;
    }
     return (_First);
}

template <  class _FwdIt,
          class _Ty >  inline
_FwdIt lower_bound(_FwdIt _First, _FwdIt _Last,  const _Ty &_Val)
{
     // find first element not before _Val, using operator<
    _ASSIGN_FROM_BASE(_First,
                      _Lower_bound(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val, _Dist_type(_First)));
     return _First;
}

lower_bound() 返回第一个“大于等于给定值" 的元素位置,其实还重载了另一个low_bound 版本,如下:

C++ Code 
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:

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
28
29
30
31
32
33
34
35
 
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

int main( void)
{
     int a[] = {  1,  10,  10,  14,  15,  16 };
    vector< int> v(a, a +  6);

for_each(v.begin(), v.end(), print_element);
    cout << endl;

vector< int>::iterator it;
    it = lower_bound(v.begin(), v.end(),  10);
     if (it != v.end())
    {
        cout << it - v.begin() << endl;
    }

it = upper_bound(v.begin(), v.end(),  10);
     if (it != v.end())
    {
        cout << it - v.begin() << endl;
    }

return  0;
}

五、数值算法(accumulate)

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
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,
          class _Ty >  inline
_Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val)
{
     // return sum of _Val and all in [_First, _Last)
     return _Accumulate(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val);
}

// TEMPLATE FUNCTION accumulate WITH BINOP
template <  class _InIt,
          class _Ty,
          class _Fn2 >  inline
_Ty _Accumulate(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func)
{
     // return sum of _Val and all in [_First, _Last), using _Func
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Func);
     for (; _First != _Last; ++_First)
        _Val = _Func(_Val, *_First);
     return (_Val);
}

template <  class _InIt,
          class _Ty,
          class _Fn2 >  inline
_Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val, _Fn2 _Func)
{
     // return sum of _Val and all in [_First, _Last), using _Func
     return _Accumulate(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Val, _Func);
}

accumulate 重载了两个版本,第一个版本实现的是累加,第二个版本带_Func 参数,可以自定义计算,比如累乘等。代码都比较好理解,就不赘述

了。看下面的示例代码4:

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
28
29
30
31
32
33
 
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <numeric>
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

int mult( int a,  int b)
{
     return a * b;
}

int main( void)
{
     int a[] = {  1,  2,  3,  4,  5 };
    vector< int> v(a, a +  5);

for_each(v.begin(), v.end(), print_element);
    cout << endl;

// 累加
    cout << accumulate(v.begin(), v.end(),  0) << endl;

// 累乘
    cout << accumulate(v.begin(), v.end(),  1, mult) << endl;

return  0;
}

参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范

从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)...相关推荐

  1. 从零开始学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 2 ...

  2. 优达学城-神经网络之预测共享单车使用情况 代码分析

    优达学城-神经网络之预测共享单车使用情况 代码分析 标签(): 机器学习 代码来自于优达学城深度学习纳米学位课程的第一个项目 https://cn.udacity.com/course/deep-le ...

  3. 《从零开始学Python网络爬虫》罗攀 蒋仟 代码

    第1章 Python零基础语法入门 1.3 函数与控制语句 1.3.1 函数 1.3.2 判断语句 1.3.3 循环语句 1.4 Python数据结构 1.4.1 列表 1.4.2 字典 1.4.3 ...

  4. 从零开始完成YOLOv5目标识别(七)一种完成目标计数的简单方法

    往期文章: 从零开始完成YOLOv5目标识别(六)用接续训练完成大规模数据集训练(以FLIR为例) ​​​​​​从零开始完成YOLOv5目标识别(五)一种扩充数据集的方式 从零开始完成Yolov5目标 ...

  5. 从零开始学C++之STL(八):函数对象、 函数对象与容器、函数对象与算法

    http://blog.csdn.net/jnu_simba/article/details/9500219 一.函数对象 1.函数对象(function object)也称为仿函数(functor) ...

  6. [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)...

    首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code  1 2   template < class _Ty, cla ...

  7. [置顶] 从零开始学C++之STL(二):实现简单容器模板类Vec(vector capacity 增长问题、allocator 内存分配器)...

    首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code  1 2   template <  class _Ty,  c ...

  8. 从零开始学Pytorch(十四)之优化算法进阶

    动量 目标函数有关自变量的梯度代表了目标函数在自变量当前位置下降最快的方向.因此,梯度下降也叫作最陡下降(steepest descent).在每次迭代中,梯度下降根据自变量当前位置,沿着当前位置的梯 ...

  9. 《从零开始学Swift》学习笔记(Day 59)——代码排版

    原创文章,欢迎转载.转载请注明:关东升的博客 代码排版包括: 空行.空格.断行和缩进等内容.代码排版内容比较多工作量很多,但是非常重要. 空行 空行将逻辑相关的代码段分隔开,以提高可读性.下列情况应该 ...

最新文章

  1. 网络工程师的经典爱情观
  2. python视图函数是什么_python项目Django(视图函数)
  3. python中的magic方法
  4. 统计数组中重复元素个数
  5. 如何在Linux上部署一个简单的Django项目
  6. STM32工作笔记0096---用sprintf分配内存
  7. python如何使用 b_python中的b
  8. Atitit 防烫伤指南与规范 attilax总结
  9. 用java设计一个公司局域网_java实现局域网内单对单和多对多通信的设计思路
  10. 数字ic后端学习ing
  11. LazyAn-cocos插件开发实战
  12. python 聚类 客户细分_Python中用K-均值聚类来探索顾客细分
  13. 基于JAVA项目任务跟踪系统计算机毕业设计源码+数据库+lw文档+系统+部署
  14. Android 蓝牙手柄连接流程解析和自动化方案
  15. 【目标跟踪】基于matlab GUI帧差法结合卡尔曼滤波行人姿态识别【含Matlab源码 1127期】
  16. php文件上传(mime类型大全)
  17. python控制台图片_Python实现图像信息隐藏
  18. 一起赚美金:Niche站变现案例分享(2)
  19. 【计算机网络实验】访问控制列表NAT应用——华为eNSP(详细实验报告+代码)
  20. iphone开发 UIButton使用

热门文章

  1. python:小心类实例的属性动态绑定机制
  2. Sublime Text怎么快速建立一个html5页面模板
  3. 记一次kafka数据丢失问题的排查
  4. Part 3: Services
  5. oracle 各种日期函数格式和操作
  6. 阻塞队列BlockingQueue用法
  7. HDU 4864 Task(贪心或高斯消元)
  8. python可以调用windows资源吗_如何在Windows上用Python调用WinRar?还有问题吗
  9. python3常用模块_Python3 常用模块
  10. Java中数组在内存中的存放原理?