第10章 泛型算法

10.1概述

大多数算法定义在头文件<algorithm>中,另外在<numeric>中定义了一组数值泛型算法。

一般来说,算法不直接操作容器,而是使用迭代器访问容器中的元素,但是在对元素进行比较的时候,会依赖于元素的类型:

auto result = find(vec.cbegin(), vec.cend(), val);

如果没有查找到结果,将会返回第二个参数

10.2泛型算法

*泛型算法一般不会改变容器的大小,只有在使用inserter(插入器)的时候可能会改变

 

类型1:求和算法,始末位置&结果类型

accumulate

类型2:比较序列,始末位置1&起始位置2

equal

类型3:赋值,始末位置&值

fill、fill_n

back_inserter插入迭代器

每次给一个插入迭代器赋值,会首先调用push_back方法,将给定元素值添加到容器中。

vector<int> vec;

auto it = back_inserter(vec);

*it = 42;

fill_n(it, 10, 0);

类型4:拷贝算法,始末位置&起始位置

copy

replace_copy

*_copy//很多方法都提供了拷贝的版本

类型5排序算法与唯一值算法混合

sort(vec.begin(), vec.end() );

auto end_unique = unique(vec.begin(), vec.end() );

//算法不能操作容器,所以容器中重复的元素并没有删除,而是放在了end_unique之后

Vec.erase(end_unique, vec.end() );

10.3定制操作

对于算法中使用到的比较,我们可以自定义比较的方法,尤其是对于那些没有提供比较运算符重载的类型。

10.3.1向算法传递函数

以函数作为参数,这个参数就是一个谓词

根据谓词接受参数的多少,在标准库算法中,分为一元谓词和二元谓词

10.3.2lambda表达式

形式

[capture list] (parameter list) mutable -> return type {function body}

其中必须包含捕获列表和函数体。

捕获列表表示function body可以使用的外部变量。

mutable表示函数体中可以改变值捕获变量的值,但是因为是值传递,并不能反映到外部对应的变量中。对于引用捕获,能否改变值在与传递的是否是const类型,与mutable无关。

注意

使用lambda表达式时,编译器会创建一个对应的类,并初始化这个类的对象进行使用。其中捕获列表中的内容会是这个类的成员变量,初始化对象时使用捕获列表中的变量对成员初始化。

捕获列表可以为空,并且分为引用捕获(&)和值捕获。可以使用隐式引用捕获“[&]”,隐式值捕获“[=]”,部分值捕获“[&, a]”,部分引用捕获“[=, &a]”。

在含有判断语句的函数体中,如果return全部在判断语句中,则return type的类型推断将会为void,所以应该尽可能的书写return type。

10.3.4参数绑定

形式

auto newCallable = bind(callable, arg_list)

arg_list是按照callable参数的顺序完整书写的,其中使用_n表示newCallable中参数的位置。

例如:auto newFunc = bind(func, b, _2, c, ref(a), _1)。func有5个参数,newFunc有两个参数,在绑定中newFunc的两个参数分别对应func的第5和2个参数。

使用bind,需要包含functional头文件。

使用参数占位符,需要使用std::placeholders命名空间。

使用引用参数绑定,需要使用ref函数

#include <iostream>

#include <vector>

#include <algorithm>

#include <functional>

using namespace std;

using namespace std::placeholders;

int main() {

         // your code goes here

         vector<int> ab={22,44,55,77};

         auto v = find_if(ab.begin(),ab.end(),

         bind([=](int a,int b) -> bool {return a==b;},_1,55));

         cout<<*(v)<<endl;

         return 0;

}

10.4再探迭代器

插入迭代器

    back_inserter

    front_inserter

    inserter

instream迭代器

    istream_iterator

    ostream_iterator

反向迭代器

    可以使用反向迭代器的.base()方法得到常规迭代器

10.5泛型算法结构

泛型算法对容器的要求通常有:可读、可写、可删除、可增加、随机访问。所以每个算法都对所操作的迭代器有一定的要求。

10.5.1对应有5类迭代器

输入迭代器input iterator

输出迭代器output iterator

前向迭代器forward iterator

双向迭代器bidirectional iterator

随机访问迭代器rand-access iterator

10.5.2算法的形参模式

alg(beg, end, other args)

alg(beg, end, dest, other args)

alg(beg, end, beg2, other args)

alg(beg, end, beg2, end2, other args)

接受单个目标迭代器的算法

dest参数表示算法可以写入目的位置的迭代器,算法假定可以向这个位置中写入元素。因此,比较常见的是dest表示一个插入迭代器或者ostream_iterator。

接受第二个输入序列的算法

接受beg2和end2,表示第二个输入迭代器的范围

只接受beg2,则是第二个输入范围的首元素,并假设beg2开始的范围至少与第一个一样。

10.5.3算法命名规范

一些算法使用重载的形式传递一个谓词

unique(beg, end)//默认使用==进行比较,并确定唯一性

unique(beg, end, comp)//使用传递的谓词comp进行比较

 

_if版本的算法

find(beg, end, val)//val第一次出现的位置

find_if(beg, end, pred)//使pred为真的位置

 

区分拷贝元素的版本和不拷贝元素的版本

reverse(beg, end)

reverse(beg, end, dest)

10.6特定容器算法

链表类型list和forward_list定义了特有的sort, merge, remove, reverse, unique,因为其链表结构不同于其他容器,其数据不能够随机访问,因此只能使用其特有的算法。通用的算法不能够使用这些容器,或者对于这些容器来讲是低效率的。

另外,链表类型定义了splice成员,用于在两个链表中移动元素。

posted on 2015-09-11 15:33  峰入云  阅读(213)  评论(0编辑  收藏  举报

导航