10.5 泛型算法结构
泛型算法是在迭代器上进行操作的,所以每一个算法都需要迭代器提供它所需的操作,按照可读,可写,递增,递减等迭代器操作,算法对迭代器的操作要求可以分为5个类别。
迭代器名字 | 支持的操作 |
---|---|
输入迭代器 | 只读、不写、单遍扫描、只能递增 |
输出迭代器 | 只写不读、单遍扫描,只能递增 |
前向迭代器 | 可读可写;多遍扫描;只能递增 |
双向迭代器 | 可读可写;多遍扫描;可递增递减 |
随机访问迭代器 | 可读可写;多遍扫描;支持全部迭代器运算 |
这里的支持全部迭代器运算就是3.4节迭代器所支持的操作里面的所有操作。
每个算法都会迭代器有着**最低的要求,**如果迭代器不满足最低要求则编译报错。高级别的迭代器支持低级别迭代器的所有操作。
迭代器类型 | 必须支持的操作 | 迭代器举例 |
---|---|---|
输入迭代器 | iter1==iter2;iter1!=iter2;++iter;++iter;*iter(只能出现在赋值运算符右侧),iter->member | istream_iterator |
输出迭代器 | iter++;++iter;*iter(只能用于赋值运算符左侧) | ostream_iterator |
前向迭代器 | 上述两个的所有操作都要有 | forward_list的迭代器 |
双向迭代器 | 输入输出迭代器的操作都需要;–iter;iter– | 除了forward_list之外的所有标准库容器都必须满足双向迭代器的要求 |
随机访问迭代器 | 支持双向迭代器的所有操作;iter1<iter2;<=;>;>=;iter+n,iter+=n;-n,-=n;iter1-iter2;iter[n] | string,array,deque,vector的迭代器要求为此类迭代器,数组的指针也是此类迭代器 |
目前的疑问,多遍扫描和单遍扫描分别是什么意思
这里的意思应该是能够遍历多次,像输入输出迭代器,因为流的状态会改变,所以就算我保存了迭代器,迭代器在赋值或者其他操作中,会导致之前的迭代器失效。所以输入输出迭代器只支持单次扫描。但是前向迭代器不会这样,所以前向迭代器可以保留之前的迭代器多次遍历。
练习
10.38
已经在上面的表中列出。
10.39
如上表所属,list的迭代器属于双向迭代器,vector的迭代器属于随机访问迭代器
10.40
首先分析,copy不需要读取元素,也不需要单遍扫描,所以copy第一二个参数,要求输入迭代器,第三参数要求输出迭代器。
reverse()需要替换元素,所以需要可读写。我觉得单向迭代器应该是可以的,不过需要计数器和多次遍历。
不过C++标准规定的是双向迭代器。
unique()需要写入元素,消除重复元素,查看编译得知是需要前向迭代器。
= =感觉很难推测。。
10.5.2 算法形参模式
大部分的函数都支持以下的四种形式
他们都接受一个输入范围(beg,end),然后后面的参数各有不同。
dest通常表示目标迭代器
如果算法只接受beg2,则序列2从begin2开始大小至少和(beg,end)一样大。
如果dest的目标位置是一个容器的迭代器,那么要求这个容器的空间是足够的,否则会造成未定义的结果。
10.5.3 算法命名规范
很多算法支持传入谓词,但是支持的方法各有不同。
比如unique,是以重载的形式支持。
但是find则是通过在find_if()来支持。
初次之外,还有_copy的算法,这些方法不改变序列本身,而是将改变后的序列传入目标位置。
练习
10.41
1.将输入范围内的old_val,替换为new_val
2.将输入范围内,满足pred表达式的,替换为new_val
3.将输入范围类的old_val,替换为new_val,并传入dest指向的目标位置
4.将输入范围内,满足pred表达式的,替换为new_val,并传入dest指向的目标位置
10.6 特定容器算法
有些容器可以使用泛型算法,但是使用泛型算法的效率很低,为了解决这个问题,有些容器对算法有自己的容器。
比如list和forward_list。
这个splice其实就是移动元素。
不同于泛型算法,这些定于在类中的算法,通常会改变容器的低层大小,这很容易理解,因为算法不是通用的,所以可以为了提高效率做一些优化。
如果一个算法有通用版本和容器自带版本,那么选择容器自带的版本
练习
10.42
list<string> slst = { "a","c","a","e123","1ca","aaa","aaa","z123","q","casd123","asdas" };
slst.sort();
slst.unique();
std::ostream_iterator<string> oiter(cout, " ");
std::copy(slst.begin(), slst.end(), oiter);