第十章 泛型算法
10.1 概述
1、与泛型算法相关的头文件
大多数算法定义在头文件algorithm中
头文件numeric定义了数值泛型算法
2、算法不会执行容器操作
算法不执行容器操作(上一章介绍的容器函数),而是使用迭代器。
迭代器的使用令算法不依赖于容器类型(有些容器有这个函数,有些容器没有这个函数)
10.2 初始泛型算法
1、accumulate
设置和的初始值,计算给定范围内的和
它将第三个参数作为求和的起点,并且默认序列中元素的类型与第三个参数可以相加,并且类型兼容。
2、对于只读算法,最好使用常量类型的迭代器
3、equal
确定两个序列是否保存相同的值
要求第二个序列的长度大于等于第一个序列
4、fill
将给定值赋予范围中的每个元素
5、fill_n
fill的基地址+偏移版本
像这种向目的位置迭代器写入数据的算法假定目的位置足够大,能容纳要写入的元素。否则会发生灾难性错误
6、插入迭代器
back_inserter是定义在头文件iterator中的一个函数,通过它可以获取插入迭代器。
7、copy
将一个范围的值拷贝到另一个地方
返回值是拷贝目的地址的尾后迭代器end
8、replace及拷贝版本算法
replace读入一个序列,并将其中所有等于给定值的元素都改为另一个值
一般版本会直接替换原有序列中的值,这样会破坏源数据
而下面的拷贝版本则会将保存到新的序列中,原有序列则保持不变
9、sort
接受两个迭代器表示范围,按默认<的比较模式从小到大地排序
原序列:
排序后的序列:
10、unique
该函数重排输入序列,将不重复的值放在前面,重复的值放在后面。返回尾端第一个重复值的迭代器
10.3 定制操作
1、谓词
①、谓词版本的sort函数
sort函数会将满足函数isShorter要求的元素排在前面(返回true)
②、stable_sort 稳定排序函数
该算法维持相等元素原有顺序
2、lambda表达式
前置知识——调用运算符:
lambda表达式什么时候用?
①、介绍lambda
[捕获列表] (参数列表)-> 返回值类型 {函数体}
可以忽略参数列表和返回值类型,但是必须永远包含捕获列表和函数体
②、lambda的调用
③、lambda的返回类型
在编写lambda时如果省略返回类型
当函数体中只存在一条返回语句时,会根据该返回语句自动推断返回类型
当函数体中存在除了返回语句之外的其它语句时,会默认返回void类型。
④、lambda的捕获列表
一个lambda只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数体中使用该变量
3、for_each
对序列中的每个元素都调用此对象
4、再探lambda
①、lambda本身的类型
每定义一个新的lambda,就生成一个新的类型
②、捕获列表的方法
-
值捕获
-
引用捕获
当使用引用捕获时,需要保证在使用lambda表达式时引用变量是存在的。
并且当返回值是引用该引用值时,需要保证返回时引用变量也是存在的。 -
隐式捕获
-
混合捕获
尽可能将捕获简单化
5、参数绑定
①、定义
我的理解是相当于函数接口加了一层中间层,在中间层进行一些处理后显示给用户调用。
后面的参数列表对应的是callable里面的所需的参数。
返回值可以理解为一个中间层函数。一般给用户调用的也就是这个中间层函数。
②、参数列表中的占位符
占位符包含在命名空间std::placeholders中,使用前需要先使用命名空间。
而placeholders则定义在functional头文件中。
在参数列表中可以使用“_n“ n是常数,这样形式的东西来占位。
而数值n表示生成的可调用对象中参数的位置:_1为中间层函数的第一个参数,_2为中间层函数的第二个参数
③、绑定引用参数
使用函数ref
10.4 再探迭代器
迭代器的四大种类
这些迭代器都定义在iterator头文件里面
1、插入迭代器
通过一个对插入迭代器进行赋值,该迭代器将向容器插入元素
插入所指元素之前的位置
2、流输入迭代器(istream_iterator)
用例1:利用迭代器指定范围构造vector
用例2:
3、流输出迭代器(ostream_iterator)
只有具有输出运算符(<<)的类型才能定义流输出迭代器
用例1:
用例2:
4、反向迭代器
反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。其递增和递减操作的含义会颠倒过来
下面带r版本的函数获取的才是反向迭代器
用例:逆序打印
①、反向迭代器转换为正向迭代器
输入一串以逗号为间隔的单词字符串:
结果会打印为TSAL,正好是LAST的逆序
这里需要使用反向迭代器的成员函数base来讲自己转换为普通迭代器
左闭合性
10.5 泛型算法结构
1、5类迭代器
泛型算法需要传入指定级别的迭代器才能实现功能
①、输入迭代器
只读、不写;单遍扫描,只能递增
②、输出迭代器
只写、不读;单遍扫描,只能递增
③、前向迭代器
可读可写;多遍扫描,只能递增
④、双向迭代器
可读可写;多遍扫描,可递增递减
⑤、随机访问迭代器
可读可写,多遍扫描,支持迭代器的全部运算
2、算法形参模式
①、接受单个目标迭代器算法
使用该模式的算法时需要保证目的地址有充足的空间
②、接受第二个输入序列的算法
3、算法命名规范
①、重载形式传递谓词
接受谓词的算法一般与普通算法重载
②、_if版本
接受一个谓词
③、_copy:区分拷贝和不拷贝
第一个版本的函数:当传入lambda表达式的i为奇数时,返回值 i%2 将会为1,也就是true。满足谓词的判断,所以将会触发remove,删除该元素。
第二个版本的函数:第一版将奇数元素删除完之后,剩下偶数元素拷贝到v2中
10.6 特定容器算法
链表list和forward_list有自己特有的成员函数版本算法。
因为链表不支持随机访问,如果使用通用版本会导致效率很低。所以库里面内置了成员函数版本的算法。
再遇到它们两个时,应该优先使用成员函数版本的算法,而不是通用算法。
这些特定版本的算法都会改变容器