4.迭代器配接器
c++标准库提供了很多预定义的特殊迭代器,即所谓的迭代器配接器(iterator adapters).
迭代器配接器使算法能够以逆向,安插模式进行工作,还可以和流配合。
1.逆向迭代器
Reverse是一种配接器。他能定义递增运算符和递减运算。使其行为倒置。算法一逆序来处理元素,所有的容器都允许使用reverse迭代器来遍历元素。
reverse_iterator与iterator都继承自_Iterator_base,它们是可以相互转换的。
- 调用reverse_iterator的base()方法可以获取”对应的”iterator。
- 可以用iterator构造一个”对应的”reverse_iterator。
例子:
#include<iterator>
void printItem(int elem){
cout << elem << " ";
}
--------------省略-------------
vector<int> vec2 = {1,2,3,4,5,6,7,8};
vector<int>::iterator iter=vec.being()+5;
vector<int> ::reverse_iterator riter(iter);//用iter初始化逆向迭代器
cout<<"iter:"<<*iter<<endl;
cout<<"riter: "<<*riter<<endl;
//正向
cout << " vec2: ";
for_each(vec2.begin(), vec2.end(), printItem);
cout << endl;
//逆向输出
cout << " vec2: ";
for_each(vec2.rbegin(), vec2.rend(), printItem);
cout << endl;
---------------省略--------------
结果为:
iter:6
riter: 5
vec2: 1 2 3 4 5 6 7 8
vec2: 8 7 6 5 4 3 2 1
当我们用普通迭代器初始化一个逆向迭代器的时候,我们看iter指向的是6,但是逆向迭代器初始化后指向的却是5.
这是因为:
1. 普通迭代器: begin()指向第一个元素,end()指向末尾元素的后一个位置,区间为左闭右开[first,last)
2. 逆向迭代器的物理位置和逻辑位置:
(1). 物理位置: begin() == rend(), end() == rebegin()
(2). 逻辑位置: 为了保证逆向迭代器和普通迭代器的概念一致性:rbegin()指向end()-1即最后一个元素,rend()指向begin()-1即第一个元素前的位置。这就是逻辑位置。
通过图可以看出
1. 反向迭代器的物理位置 为普通迭代器的位置。
2. 反向迭代器的逻辑位置就是普通迭代器的前一个位置
因此,普通迭代器 iter指向 6;
那么iter初初始化逆向迭代器riter的位置为:5;即iter的前一个位置;
【本段内容引用自:C++迭代器之’反向迭代器’】
2.插入型迭代器
- Insert迭代器为Inserters,用来将“赋值新值”操作转换为“安插新值”操作;
- 算法可以执行安插行为而非覆盖行为
- 所有Insert迭代器属于Output迭代器类型,只提供赋值能力;
Insert迭代器吧上述的赋值动作转为安插动作
- 运算符“*”传回迭代器当前的位置
- 然后由
operator=
赋值新值
Insert迭代器的技巧:
operator*
在实际操作中被认为是一个无实际操作的动作,简单传回*this
,对Insert迭代器来说,*pos
和pos
等价;- 赋值动作被转化插入动作;事实上Insert迭代器会调用容器的
push_back(),push_front(),insert()
等成员函数;
对与一个insert迭代器,插入新值: *pos = value
;
Insert迭代器的分类:区别在于插入位置
- 后插入型
- 前插入型
- 产生型
分类:
名称 | class | 其所调用的函数 | 生成函数 |
---|---|---|---|
BackInserter | back_insert_iterator | push_back | back_inserter(cont) |
FrontInserter | fonrt_insert_iterator | push_front | front_inserter(cont) |
GeneralInster | insert_iterator | Insert(pos,value) | Inserter(cont, pos) |
容器本身需要支持Insert迭代器所调用的函数,否则该Insert迭代器就不可用;
- back_inserter: 支持vector,deque,list, string·
容器
- front_inserter: 支持deque, list
容器
3. 流迭代器
- 流迭代器是一种迭代器配接器,可以把流当做算法的原点和终点;
- 流迭代器是特殊用途的输入和输出迭代器,程序能管理与I/o相关的数据;
- istream 迭代器从input stream中读取元素;ostream迭代器对Output stream写入元素。
- 流迭代器的特殊形式:stream缓冲区迭代器
1.ostream迭代器
ostream迭代器将值写入到Output stream中。
ostream迭代器赋值操作转化为运算符operator<<
ostream迭代器的各项工作 |
---|
算式 | 效果 |
---|---|
ostream_iterator<T>(ostream) | 为ostream产生一个ostream迭代器 |
ostream_iterator<T>(ostream,delim) | 为ostream产生一个ostream迭代器,各元素间以delim作为分隔符 |
*iter | 无实际操作 |
Iter = value | 将value写入到ostream, 如ostream << value |
++ iter | 无实际操作 |
Iter ++ | 无实际操作 |
1. 生成迭代器的时候,必须提供一个 outputstream作为参数,迭代器会将元素写入到此Output stream身上;
2. 另一个参数可有可无,是一个字符串,作为元素之间的分隔符。分割符的类型 cosnt char*
,如果使用string类型,需要转换,如使用c_str()
例子:
---------------省略-------------------
vector<int> vec2 = {1,2,3,4,5,6,7,8};
cout << " vec2: ";
copy(vec2.begin(), vec2.end(), ostream_iterator<int>(cout," "));
cout << endl;
---------------省略-------------------
结果为:
vec2: 1 2 3 4 5 6 7 8
2. istream迭代器
- 用于从input stream中读取元素。
- 一般经过从input迭代器的通用接口,利用
operator>>
读取元素,操作可能失败,算法需要知道终点 - 为了解决这个问题: 使用 end-of-stream,他利用istream迭代器默认构造函数生成。
- 只要读取失败一次,istream迭代器就变成了end-of-stream,读取结束,可以将两个迭代器进行比较
istream迭代器的操作:
算式 | 效果 |
---|---|
istream_iterator<T>() | 产生一个end-of-stream迭代器 |
istream_iterator<T>(istream) | 为istream产生一个istream迭代器(可能立即读取一个元素) |
*iter | 传回先去读取的值(如果构造函数没有读取第一个元素的值,则本式子执行读取任务) |
iter->member | 传回读取元素的成员 |
++iter | 读取下一个元素并返回其位置 |
iter ++ | 读取下一个元素,传回迭代器指向的前一个元素 |
iter1 == iter2 | 检验 iter1 和iter2是否相等 |
iter1!= iter2 | 检验iter1 和iter2是否不等 |
istream迭代器的模板:
template< class T,class CharT = char,
class Traits = std::char_traits<CharT>,
class Distance = std::ptrdiff_t >
class istream_iterator: public std::iterator<std::input_iterator_tag, T, Distance, const T*, const T&>
- 第一个参数是数据类型
- 第二个和第三个参数确定stream类别
- 第四个参数表示指定迭代器距离表示的型别;
两个istream迭代器相等的条件:
- 两者都是end-of-stream迭代器
- 两个都可以进行读取操作,并指向相同的stream;
例子:
---------------省略----------------
istream_iterator<int> inputcin(cin);//cin迭代器
istream_iterator<int> eof;//流结束迭代器
while (inputcin != eof){
vec1.push_back(*inputcin);
++inputcin;
}
---------------省略----------------
使用`CTRL + Z`输入空白,结束
结果为:
1 2 3 4 5 6 7 8 9
^Z
vec1: 1 2 3 4 5 6 7 8 9