10.4 再探迭代器
标准库的头文件iterator,除了定义了容器的迭代器之外,还定义了一些额外的迭代器。
- 插入迭代器 insert iterator
- 流迭代器 stream ierator
- 反向迭代器 reverse iterator
- 移动迭代器
接下来总结每个迭代器具体是做什么的
10.4.1插入迭代器
插入迭代器是一种迭代器适配器,其接受一个容器,生成一个迭代器,对该迭代器赋值时,这个迭代器将调用容器操作将赋值的元素添加进容器。
插入迭代器有三个。
1.back_inserter
2.front_inserter
3.inserter
backi_inserter调用容器的push_back()操作,前提是容器有push_back()操作,添加之后的元素为顺序
front_inserter()调用容器的push_front()操作,前提是容器有push_front()操作,添加之后的元素位逆序。
inserter()需要指定容器和插入的位置,指向insert操作,inserter将元素插入到指定的元素之前,所以添加之后的元素为顺序。
插入迭代器支持的操作:
其实只有赋值有用,其余的操作返回的都是插入迭代器自己。
练习
10.26
有什么不同指出,已经在上面写出来了
10.27
vector<string> vec = { "a","c","a","e123","1ca","aaa","aaa","z123","q","casd123","asdas" };
deque<string> dq;
std::sort(vec.begin(),vec.end());
std::unique_copy(vec.begin(),vec.end(),std::back_inserter(dq));
for (const auto& item:dq) {
cout << item << endl;
}
cout << "size:" << dq.size() << endl;
10.28
错误记录:这里我犯了一个错误就是,认为传给算法的迭代器在每次赋值的使用都调用一次,所以inserter传入begin(),每次都在首元素之前插入,那插入的元素不就是逆序吗,但是其实是只在调用时begin()指的还是首元素或者最后一个元素的下一位置,在插入了其他的元素之后,它就不再是首元素了。
vector<int> vec = {1,2,3,4,5,6,7,8,9};
vector<int> vec_1;
list<int> lst_1;
deque<int> dq_1;
//顺序
std::copy(vec.begin(), vec.end(), std::back_inserter(vec_1));
//逆序
std::copy(vec.begin(), vec.end(), std::front_inserter(lst_1));
//这是顺序。。。= =
std::copy(vec.begin(),vec.end(),std::inserter(dq_1,dq_1.begin()));
for (const auto& item:vec_1) {
cout << item << std::ends;
}
cout << endl;
for (const auto& item : lst_1) {
cout << item << std::ends;
}
cout << endl;
for (const auto& item : dq_1) {
cout << item << std::ends;
}
cout << endl;
10.4.2 iostream迭代器
标准库定义了用于IO类型的迭代器。
1.istream_iterator
2.ostream_iterator
istream_iterator操作
创建istream_iterator需要指定迭代器类型,在初始化时,可以传入流对象,也可以使用默认初始化,如果是默认初始化则表示尾后迭代器。如果传入了流对象,则从该流中读取数据。
对istream_iterator的操作流程一般是:
std::istream_iterator<int> int_input(cin);
std::istream_iterator<int> eof;
vector<int> vec;
while (int_input!=eof) {
vec.push_back(*int_input++);
}
使用*iter来获取流中的元素,使用iter++,从迭代器中读取下一个元素。
怎么用
我们可以在一些算法中使用istream_iterator.
istream_iterator<int> in(cin),eof;
cout<<accumulate(in,eof,9)<<endl;
该算法将从标准输入中读取值。
当我们使用一个流迭代器绑定到一个流上时,迭代器不一定立刻从流中读取数据,也可以在调用时,再读取。
这里没有给出实际的代码,我也不好理解这句话的意思
ostream_iterator
ostream_iterator在初始化时,必须绑定对象,同时可以添加一个C风格字符串,在每次输出时都会添加这么一个字符串。
直接使用iter=value,就可以向绑定的流中输出数据。
*iter,++iter,iter++,都返回的是自己。
虽然这三个操作没用,但是一般还是建议用上,一个是保持风格的统一,一个是如果迭代器变了,程序的修改程度也不大。
具体的操作,看练习
对于流迭代器,只要类类型,重载了>>就能够使用istream_iterator,只要重载了<<就能够使用ostream_iterator.
练习
10.29
std::ifstream fin("phone.txt");
//需要指定对象的类型
std::istream_iterator<string> in_iter(fin);
// 尾后迭代器
std::istream_iterator<string> eof;
vector<string> str_vec;
while (in_iter!=eof) {
str_vec.push_back(*in_iter++);
}
std::ostream_iterator<string> out_iter(cout," ");
for (const auto& item:str_vec) {
*out_iter++ = item;
}
10.30
vector<string> vec = { "a","c","a","e123","1ca","aaa","aaa","z123","q","casd123","asdas" };
std::istream_iterator<int> int_input(cin);
std::istream_iterator<int> eof;
//std::sort();
vector<int> vec;
while (int_input!=eof) {
vec.push_back(*int_input++);
}
std::ostream_iterator<int> int_output(cout," ");
std::sort(vec.begin(),vec.end());
std::copy(vec.begin(), vec.end(), int_output);
//std::unique_copy(vec.begin(), vec.end(), int_output);
10.31
std::unique_copy(vec.begin(), vec.end(), int_output);
10.32
没有1.6节的源码,后续学习到重载运算符再补上
10.33
std::ifstream f("data.txt");
std::istream_iterator<int> f_input(f),eof;
std::ofstream file1("jishu.txt"), file2("oushu.txt");
std::ostream_iterator<int> out_iter_1(file1," "),out_iter_2(file2,"\n");
while (f_input!=eof) {
if (*f_input%2==1) {
*out_iter_1++ = *f_input;
}
else {
*out_iter_2++ = *f_input;
}
f_input++;
}