从零开始学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
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[] = {  132345 };
    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[] = {  123456 };
    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[] = {  11010141516 };
    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[] = {  12345 };
    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++编程规范


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20 种物体破剖面图,真正的让你脑洞大开

全世界只有3.14 % 的人关注了数据与算法之美有很多东西的内部世界十分复杂&#xff0c;单纯的从表面看难以窥其精锐&#xff0c;今天咱们来看那些被劈成两半展示横截面的东西&#xff1a;1.安全气囊2.打火机3.各种枪械消音器4.集装箱船5.路虎车6.曲棍球头盔7.人类心脏8.数码相机…

一个女孩子对老公/男朋友的要求

*有点害羞&#xff0c;但曾在分别的街头&#xff0c;大声说我爱你。 *同我去庙里求签&#xff0c;轻轻捉住我的手一同跪下。 *言而有信。 *从来不迟到--我迟到他不生气。 *拥抱很久、很紧--每次我起身时几乎是需要慢慢推开他。 *睡得比我迟一点&#xff0c;醒来早一点。 …

你的公司内卷化了吗?

大家看上去都很忙&#xff0c;但就是没结果怎么办&#xff1f;忙有结果都是好的&#xff0c;没有结果都是问题。其实可以从三方面来看这个问题&#xff1a;1、没有正确找到方法大家都在教科书学过一只乌鸦喝水的故事。故事告诉人们遇到困难不要放弃&#xff0c;要运用身边可以利…

java.awt.headless_以编程方式设置java.awt.headless = true

小编典典我正在使用一个main()类&#xff0c;该类在常量(和其他静态代码)中静态加载JFreeChart的不同部分。将静态加载块移到类的顶部解决了我的问题。这不起作用&#xff1a;public class Foo() {private static final Color COLOR_BACKGROUND Color.WHITE;static { /* too l…

飘逸的python - hack输出流便于调试

当项目有很多文件时&#xff0c;要找出控制台的输出是在哪里print出来的很麻烦&#xff0c;不过这事对于强大的python来说小菜一碟。 先上代码和效果&#xff0c;再说明。 import sys,traceback class mystdout:stdout sys.stdoutdef write(self,_str):if _str ! \n:filepath…

每日一笑 | 3 X 4 = ?

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

ASP.NET下MVC设计模式的实现

1 MVC设计模式简介 MVC由Trygve Reenskaug提出&#xff0c;首先被应用在SmallTalk-80环境中&#xff0c;是许多交互和界面系统的构成基础。MVC结构是为那些需要为同样的数据提供多个视图的应用程序而设计的&#xff0c;它很好的实现了数据层与表示层的分离。MVC作为一种开发模型…

堵俊平:开放治理是开源社区的终极之路 | DEV. Together 2021 中国开发者生态峰会...

内容来源&#xff1a;2021 年 6 月 5 日&#xff0c;由 SegmentFault 思否主办的 2021 中国开发者生态峰会圆满落幕。会上&#xff0c;开放原子开源基金会 TOC 主席、华为计算开源总经理堵俊平发表了《开放治理&#xff1a;开源社区的终极之路》的主题演讲。分享嘉宾&#xff1…

php防止快速刷新代码(分享)_php防止网站被刷新的方法汇总

本文实例讲述了php防止网站被刷新的方法。分享给大家供大家参考。具体方法如下&#xff1a;对于像采用WP建设的站来说&#xff0c;频繁的刷新会导致数据库吃紧。下面附上一段代码,防止频繁的刷新造成的死机情况。方法一,代码如下:session_start();$k$_GET[k];$t$_GET[t];$allow…

2013年7月27日杂记

今天周六加班一直在开会&#xff0c;早上起床后看了JS精粹一书&#xff0c;感觉里面讲的东西真是很好&#xff0c;我应该学习&#xff0c;应该记住其中的知识点然后多实践多真正做出些东西。这会头很晕有点想睡觉&#xff0c;但潜意识居然想看电视&#xff0c;居然不能管住自己…

每日一笑 | 谷歌能严谨到什么地步?

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

浏览器的定制与扩展

下载源代码 本文分如下章节&#xff1a; 前言 在MFC中使用浏览器 怎样扩展或定制浏览器 定制鼠标右键弹出出菜单 实现脚本扩展(很重要的external接口) C代码中如何调用网页脚本中的函数 定制消息框的标题 怎样定制、修改浏览器向Web服务器发送的HTTP请求头 怎样修改浏览器标识 …

通过反射实现IOC功能

闲来没事&#xff0c;自己就想着根据反射可以自己写一个简易的IOC组件。IOC组件说白了就是根据反射实例化对应的接口。废话不多说&#xff0c;开始说说我的解决方案。1、项目结构图&#xff1a;IOCTest为web MVC项目。Common 通过配置文件实例化对应的接口IBLL定义的接口BLL实现…

php 分享微博,php微信分享到朋友圈、QQ、朋友、微博

本文实例为大家分享了php微信分享到朋友圈、QQ、朋友、微博的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下前台代码wx.config({debug: false,appId: "{$signPackage[appId]}",timestamp: "{$signPackage[timestamp]}",nonceStr: "{$signP…

base函数

Basename函数 参考资料 http://monkeymusic.blog.163.com/blog/static/4797639200912533652666/ 解释 basename - strip directory and suffix from filenames 去除给出字符串的前缀例子 Shell命令&#xff1a;basename a/b/c/d/test/a.ppt 输出&#xff1a;a.ppt 可以在后面添…

如果这个世界都不按套路出牌将会变成怎么样。。。 | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;请你有话“直”说↓ ↓ ↓

晁錯論

晁錯論 〈晁錯論〉 天下之患&#xff0c;最不可為者&#xff0c;名為治平無事&#xff0c;而其實有不測之憂。坐觀其變&#xff0c;而不為之所 &#xff0c;則恐至於不可救&#xff1b;起而強為之&#xff0c;則天下狃於治平之安而不吾信。惟仁人君子豪傑之士&#xff0c; 為能…

关于面试,避开这几点,成功几率更大~~~

概述 又是一个大学毕业季&#xff0c;刚好最近几年参与过很多面试&#xff0c;把其中遇到的一些具有“代表性”的面试场景总结出来和小伙伴聊聊&#xff0c;助力小伙伴跳过一些面试大坑(强烈希望)。对于面试&#xff0c;有很多小伙伴认为只是聊技术、聊能力&#xff0c;其实不仅…

脚本语言php是什么意思,php是什么脚本语言

PHP是一种简单的&#xff0c;面向对象的&#xff0c;解释型的&#xff0c;健壮的&#xff0c;安全的&#xff0c;性能非常之高的&#xff0c;独立于架构的&#xff0c;可移植的&#xff0c;动态的脚本语言。PHP具有和JAVA类似的Class关键字。因为不需要虚拟机&#xff0c;以致速…

[IOS地图开发系类]2、位置解码CLGeocoder

2019独角兽企业重金招聘Python工程师标准>>> 接第一步的操作&#xff0c;获取到地址信息经纬度后&#xff0c;我们可以对其进行解码&#xff0c;解码采用的CLGeocoder这个类&#xff0c;使用方式如下&#xff1a; 1、在ViewControlelr.m文件中声明一个CLGeocoder的…