【Primer C++学习笔记】10. 泛型算法

10. 泛型算法

可以用于不同类型的元素和多种容器类型(标准库类型比如vector和list,还包括内置的数组类型)

10.1 概述

10.2 初始泛型算法

10.2.1 只读算法

10.2.2 写容器元素的算法

10.2.3 重排容器元素的算法

10.3 定制操作

10.3.1 向算法传递函数

10.3.2 lambda表达式

10.3.3 lambda捕获和返回

10.3.4 参数绑定 bind

10.4 再探迭代器

10.4.1 插入迭代器

10.4.2 流迭代器

10.4.3 反向迭代器

10.4.4 移动迭代器

10.5 泛型算法结构

10.6 特定容器算法


10.1 概述

迭代器令算法不依赖于容器,但算法依赖于元素类型的操作。

算法本身不会执行容器的操作,只会运行于迭代器之上执行迭代器的操作。


10.2 初始泛型算法

标准库提供的算法具有一致的结构,前两个参数(迭代器)表示范围(对该范围内的元素进行操作)。不同的算法对范围内的元素使用方式不同,通过算法是否读取元素、改变元素或是重排元素顺序了解不同的算法。

10.2.1 只读算法

本身不改变元素,例如find、count、accumulate(求和)、equal(判断是否相同)等函数。

10.2.2 写容器元素的算法

序列原大小要大于等于算法写入的元素数目,由于算法不会执行容器操作,因此自身不可能改变容器大小,例如fill(在指定范围内填充)、fill_n(填充指定数目个值)、copy、replace函数。

fill:

fill_n:

为了保证算法有足够空间容纳数据,可以使用插入迭代器back_inserter,它是定义在头文件iterator中的函数。通过插入迭代器可以向容器中添加元素。

常常使用back_inserter创建一个迭代器作为算法的目的位置使用。back_inserter接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器,使用此迭代器赋值时,赋值运算符会调用push_back将元素添加到容器中。因此最终fill_n语句向vec末尾添加了10个值为0的元素。

copy:

replace:

将所有等于第一个值的元素替换成第二个值:

如果希望保留原序列不变,可以调用replace_copy函数产生一个新的序列,其中提供一个参数指出调整后的序列的保存位置:

10.2.3 重排容器元素的算法

调整容器中元素的顺序,例如sort函数。例如已有一个vector,希望使得vector中每个单词只出现一次:

其中unique并不真的删除元素,只是覆盖相邻的重复元素。


10.3 定制操作

通过用户自己定义的操作来替代默认运算符。例如调用sort的过程中,希望的排序顺序与<定义的顺序不同(<是按照大小排序或者按照字典序排列),此时需要重载sort的默认行为。

10.3.1 向算法传递函数

例如希望单词按照长度排序,长度相同的再按字典序排列,因此需要使用sort的重载版本,该版本接受第三个参数,此参数是一个谓词。

谓词:是一个可调用的表达式,返回结果是一个能用作条件的值。其中一元谓词只接受单一参数,二元谓词有两个参数。

 

 为了使相同长度的元素按字典序排列,可以使用stable_sort算法,稳定排序算法维持相等元素的原有顺序(elimDups在上一节):

10.3.2 lambda表达式

根据算法接受一元谓词还是二元谓词,算法必须严格接受一个或两个参数。lambda表达式是一种可调用对象(可调用对象包括函数、函数指针、重载了函数调用运算符的类以及lambda表达式),通过向算法传递一个可调用对象实现相应功能。

与isShorter函数完成相同功能的lambda:

空的捕获列表表名此lambda不适用它所在函数中的任何局部变量,使用此lambda调用stable_sort如下:

另一个例子是求大于等于一个给定长度的单词有多少,将此函数命名为biggies:

获取指向第一个满足size()>=sz的元素的迭代器:

可以使用find_if算法查找第一个具有特定大小的元素,find_if算法接受一对迭代器表示一个范围

计算满足size>=sz元素的数目:

利用find_if返回的迭代器计算从它到words的末尾一共有多少个元素

 

打印长度大于等于给定值的单词:

使用for_each算法,此算法接受一个可调用对象并对输入序列中每个元素调用此对象。

最后,完整的biggies函数如下:

10.3.3 lambda捕获和返回

10.3.4 参数绑定 bind


10.4 再探迭代器

标准库在头文件iterator中还定义了额外几种迭代器:

10.4.1 插入迭代器

插入迭代器被绑定到一个容器上,可用来向容器插入元素。

插入迭代器有三种类型,差异在于元素插入的位置:

10.4.2 流迭代器

流迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流。

istream_iterator读取输入流,ostream_iterator向一个输出流写数据。这两种迭代器将对应的流当作一个特定类型的元素序列来处理。

10.4.3 反向迭代器

反向迭代器向后而不是向前移动,除了forward_list之外的标准库容器都有反向迭代器。对于反向迭代器,递增递减操作的含义会颠倒过来,递增(++it)一个反向迭代器会移动到前一个元素,递减(it--)一个反向迭代器会移动到下一个元素。

10.4.4 移动迭代器

移动迭代器不是拷贝其中的元素,而是移动它们。


10.5 泛型算法结构

算法所要求的迭代器操作可以分为5个迭代器类别,每个算法都对其迭代器参数指明需要哪一类:


10.6 特定容器算法

list和forward_lisy定义了几个成员函数形式的算法,定义了独有的sort、merge、remove、reverse和unique:

 

链表类型还定义了链表数据结构特有的spice算法:

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值