一、移除性算法 (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,则传入到

接着遍历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 会使当前迭代器失效,但可以返回下一个迭代器,故如果需要在遍历中删除,下面的做法才是正确的:

 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
 
#include <iostream>
#include <vector>

using namespace std;

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

//for (vector<int>::iterator it=v.begin(); it!=v.end(); ++it)
    //{
    //  if (*it == 3)
    //      v.erase(it);          ERROR!
    //  else
    //      cout<<*it<<' ';
    //}

for (vector<int>::iterator it = v.begin(); it != v.end();)
    {
        if (*it == 3)
            it = v.erase(it);
        else
        {
            cout << *it << ' ';
            ++it;
        }
    }

cout << endl;
    return 0;
}

示例代码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;
}

此外,sort 有个坑,如果你自己传递比较逻辑,需要注意,如下:

四、已序区间算法 (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++编程规范

剩下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. 背景建模技术(二):BgsLibrary的框架、背景建模的37种算法性能分析、背景建模技术的挑战

    背景建模技术(二):BgsLibrary的框架.背景建模的37种算法性能分析.背景建模技术的挑战 1.基于MFC的BgsLibrary软件下载 下载地址:http://download.csdn.ne ...

  3. 变动性算法源代码分析与使用示例(copy_backward、 transform、 replace_copy_if 等)

    首先回顾前面的文章,我们把for_each 归类为非变动性算法,实际上它也可以算是变动性算法,取决于传入的第三个参数,即函数 指针.如果在函数内对容器元素做了修改,那么就属于变动性算法. 变动性算法源 ...

  4. 非变动性算法源代码分析与使用示例( 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 ...

  5. Https与Http,SSL,DevOps, 静态代码分析工具,RFID, SSH, 非对称加密算法(使用最广泛的一种是RSA), 数字签名, 数字证书

    在URL前加https://前缀表明是用SSL加密的. 你的电脑与服务器之间收发的信息传输将更加安全. Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定. http和h ...

  6. HashMap的结构算法及代码分析

    HashMap算是日常开发中最长用的类之一了,我们应该了解它的结构跟算法: 参考文章: http://blog.csdn.net/vking_wang/article/details/14166593 ...

  7. 圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单

    圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单   ////  CircleCore.h//  Quartz////  Created by 仙人掌 on 12 ...

  8. KMP算法以及优化(代码分析以及求解next数组和nextval数组)

    KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...

  9. 编程算法 - 圆圈中最后剩下的数字(递推公式) 代码(C++)

    圆圈中最后剩下的数字(递推公式) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 0,1...,n-1这n个数字排成一个圆圈, 从数字0開始 ...

随机推荐

  1. HBase中的Client如何路由到正确的RegionServer

    在HBase中,大部分的操作都是在RegionServer完成的,Client端想要插入,删除,查询数据都需要先找到相应的RegionServer.什么叫相应的RegionServer?就是管理你要操 ...

  2. mormot解析天气预报JSON数据

    mormot解析天气预报JSON数据 uses SynCommons; constjson2 = '{' + #13#10 +'"error":0,' + #13#10 +'&qu ...

  3. Android源码大放送之material design类型

    本文转载自:http://www.apkbus.com/android-243232-1-1.html 鉴于大家对源码的渴望,就算自己辛苦一点也要满足大家的需求,查看了几百个源码之后终于筛选出了这些精 ...

  4. memcache在大型网站的应用策略

    [部署策略] 基于memcached的 slab 和dump的内存管理方式,它产生的内存碎片比较少,不需要OS去做繁杂的内存回收,所以它对CPU的占用率那是相当的低.所以建议将它跟占用CPU较高 的W ...

  5. mysql 中 unix_timestamp和from_unixtime函数

    1.unix_timestamp 将时间转化为时间戳.(date 类型数据转换成 timestamp 形式整数) 没传时间参数则取当前时间的时间戳 mysql> select unix_time ...

  6. 用 Git Hooks 进行自动部署

    原文发表于 http://ourai.ws/posts/deployment-with-git-hooks/ 昨天开始接手开发公司前端团队的主页,在稍微修改点东西后推送到远程仓库想看下线上结果时发现并 ...

  7. IntelliJ IDEA 插件开发视频教程

    IntelliJ IDEA 插件开发视频教程 学习了:http://wiki.jikexueyuan.com/project/intellij-idea-tutorial/plugins-develo ...

  8. [Angular-Scaled web] 4. Using ui-router's named views

    In the previous post, we use $stateProvider deriect to root url and using MainCtrl, categories.tmpl. ...

  9. C#基础视频教程5.1 如何编写简单的超级热键

    我们上一节介绍了编写简单计算器,实际上也是出于实用角度(这个计算器只要你肯改,肯定能做的比微软自带的计算器好用).这一节介绍做简单的超级热键(所谓的超级热键是指自定义快捷键的功能) 超级热键的最关键一 ...

  10. ipv6相关

    link-local和site-local address http://blog.163.com/s_u/blog/static/13308367201052411431027/ 学习IPV6的时候 ...