除了为每个容器定义的迭代器之外,标准库在头文件iterator中还定义了额外几种迭代器。这些迭代器包括以下几种:
- 插入迭代器:这些迭代器被绑定到一个容器上,可用来向容器插入元素。
- 流迭代器: 这些迭代器被绑定到输入或输出流上,可用来遍历所关联的I0流。
- 反向迭代器: 这些迭代器向后而不是向前移动。除了forward_ list之外的标准库容器都有反向迭代器。
- 移动迭代器: 这些专用的迭代器不是拷贝其中的元素,而是移动它们。我们将在后面的13.6.2处进行详细介绍。
插入迭代器
绑定到容器中,用来向容器插入元素;
插入迭代器是一种迭代器适配器,接受一个容器生成迭代器,实现向给定容器添加元素。
相关的操作:
it= t; //在it指定位置插入值t
*it,++it,it++ //返回it
插入迭代器的三种模式
插入迭代器 | 说明 |
---|---|
back_inserter | 类似于使用c.push_back(val); |
front_inserter | 类似于使用c.push_front(val); |
inserter | 类似于使用 it = c.inserter(it,val);++it;元素被插入到给定迭代器之前的元素的地方 |
只有在容器支持push_ front(forward_list、list、deque)的情况下,我们才可以使用front_ inserter。类似的,只有在容器支持push_back(vector deque string)的情况下,我们才能使用back_ inserter.
样例:
vector<string> strs = { "hhdy","ssssdfg","asdcfgd","hh","xx","hhdyzwhy" };
auto it = inserter(strs, strs.begin()+1);
it = "abs";
//hhdy abs ssssdfg asdcfgd hh xx hhdyzwhy
auto it1 = back_inserter(strs);
*it1 = "hhh"; //it和*it=val都可以
//hhdy abs ssssdfg asdcfgd hh xx hhdyzwhy hhh
vector<string> strs1;
copy(strs.begin(), strs.end(), inserter(strs1, strs1.begin()));
//hhdy abs ssssdfg asdcfgd hh xx hhdyzwhy hhh
list<string> strs2;
copy(strs.begin(), strs.end(), front_inserter(strs2));
//hhh hhdyzwhy xx hh asdcfgd ssssdfg abs hhdy
vector<string> strs3;
copy(strs.begin(), strs.end(), back_inserter(strs3));
//hhdy abs ssssdfg asdcfgd hh xx hhdyzwhy hhh
vector<string> strs4;
copy(strs.begin(), strs.end(), inserter(strs1, strs4.begin()));
//hhdy abs ssssdfg asdcfgd hh xx hhdyzwhy hhh
//此处和strs2进行对比,看看有什么不同。
iostream迭代器(流迭代器)
虽然iostream类型不是容器,但标准库定义了可以用于这些IO类型对象的迭代器。istream_iterator 读取输入流,ostream_ iterator 向一个输出流写数据。这些迭代器将它们对应的流当作一个特定类型的元素序列来处理。通过使用流迭代器,我们可以用泛型算法从流对象读取数据以及向其写入数据。
istream_iterator 操作
操作 | 说明 |
---|---|
istream_iterator<T> in(is); | in从输入流is中读取T类型的数据,in实际上相当于此段迭代器中的begin |
istream_iterator<T> end; | 读取类型为T的istream_iterator尾后迭代器,相当于此段迭代器中的end |
in1 == in2 | in1和in2都是尾后迭代器或者绑定到相同的输入(前提二者都是读取T类型的数据) |
in1 != in2 | 非上面的描述即此描述 |
*in | 返回从流中读取的数据 |
in->mem | 等效于(*in).mem |
++in,in++ | 使用元素类型所定义的>>运算符从输入流中读取的下一个值。 |
常见用法1:
从cin读取int值存入vec
//从cin读取int值存入vec
vector<int> vec;
istream_iterator<int> int_it(cin),int_eof;
while (int_it != int_eof) {
vec.push_back(*int_it++);
}
//相当于下方代码
istream_iterator<int> in_iter(cin), eof;
vector<int> vec(in_iter, eof);
常见用法2:
从文件流读取string存入vecstr
ifstream in("文件地址");
istream_iterator<string> str_int(in),str_eof;
vector<string> vecstr;
while (str_int != str_eof) {
vecstr.push_back(*str_int++);
}
常见用法3:
使用泛型算法操作流迭代器
istream_iterator<int> intit(cin), inteof;
cout<<accumulate(intit, inteof, 0)<<endl;
ostream_iterator 操作
可以对任何具有输出运算符(<<)的类型定义ostream_iterator。
ostream_iterator必须绑定到一个指定的流,不允许空的或表示尾后位置的ostream_iterator。
ostream_iterator 操作 | 说明 |
---|---|
ostream_iterator<T> out(os); | out将类型T的值写入输出流os中 |
ostream_iterator out(os,d); | out将类型T的值写入输出流os中,每个值后都输出一个d。d指向一个空字符结尾字符数组。 |
out = val | 用<<运算符将val写入到out绑定输出流os中。 |
*out,++out,out++ | 不对out做任何事,返回out |
常用用法1:
输出
vector<int> vec{ 1,2,3,4,5 };
ostream_iterator<int> out(cout, " ");
for (int i : vec)
{
out = i;
//*out++ = i;//功能和上面的一致。
}
cout << endl;
常用用法2:
通过泛型函数打印输出
ostream_iterator<int> out_iter(cout, " ");
copy(vec.begin(), vec.end(), out_iter);
cout << endl;
常用用法3:
使用流迭代器处理类:
待补。
反向迭代器
反向迭代器是在容器从尾元素向首元素反向移动的迭代器。反向迭代器++it会移动到前一个元素,- -it会移动到后一个元素。
由于反向迭代器需要递减运算符,所以除单向链表和流迭代器外可以使用。
c.rbegin(),c.crbegin(),c.rend(),c.crend()
常用的方式1:
逆序输出:
vector<int> vec = { 1,2,3,4,5 };
ostream_iterator<int> outer_vec(cout, " ");
copy(vec.rbegin(), vec.rend(), outer_vec); //5,4,3,2,1
cout<<endl;
for (auto iter = vec.rbegin(); iter != vec.rend(); ++iter) {
cout << *iter << " "; //5,4,3,2,1
}
cout << endl;
常用的方式2:
逆序排序:
sort(vec.rbegin(),vec.rend());
常用的方式3:
输出逗号分割列表中倒数第一个单词
由于普通迭代器是左闭右开,反向迭代器是左开右闭。二者不能混合使用。从一个普通迭代器初始化一个反向迭代器,或是给一个反向迭代器赋值时,结果迭代器和原迭代器指向的不是同一个元素。
可以使用reverse_iterator的base函数,使反向迭代器返回对应的普通迭代器。
string words = "hhdy,zwhy,hhdyzwhy";
auto lword_iter = find(words.rbegin(), words.rend(), ',');
cout << string(words.rbegin(),lword_iter) << endl; //yhwzydhh
//为什么不用下面的那个格式呢?
//原因在于lword_iter是从逆向过来的,所以他是一个反向迭代器,意味着他会反向的处理string,导致无限循环,在此处卡住。
cout << string(lword_iter,words.rbegin())<<endl;
//正确格式,使用base函数进行再次反过来。
cout << string(lword_iter.base(),words.end()) << endl;//hhdyzwhy
移动迭代器
不拷贝其中元素,而是移动他们。