10.4 再探迭代器
插入迭代器有三种类型:
back_inserter,创建一个使用 push_back 的迭代器
front_inserter 创建一个使用 push_front 的迭代器
inserter 创建一个使用 insert 的迭代器,插入迭代器之前的位置
/* it是由inserter生成的迭代器 */ std::vector<int> vec1; int val =42; auto it = std::inserter(vec1,vec1.begin()); *it =42; //其效果与下面代码一致 auto it = vec1.insert(vec1.begin(), 42);//it指向新插入的元素 ++it;//递增it使它指向原来的元素
std::list<int> lst = { 1, 2, 3, 4 }; std::list<int> lst2, lst3;//空 //拷贝完成后,lst2 包含 4,3,2,1 std::copy(lst.cbegin(), lst.cend(), std::front_inserter(lst2)); //拷贝完成后,lst2 包含 1,2,3,4 std::copy(lst.cbegin(), lst.cend(), std::inserter(lst3,lst3.begin()));
IOStream 迭代器
将它们对应的流,当做一个特定类型的元素序列来处理
std::istream_iterator<int> int_iter(std::cin); //绑定一个流,从cin读取int std::istream_iterator<int> eof; //默认初始化迭代器,尾后迭代器 std::vector<int> vec; while (int_iter != eof){ //后置递增运算读取流,返回迭代器的旧值 //解引用迭代器,获得从流读取的前一个值 vec.push_back(*int_iter++); } } //元素范围是通过关联的流中读取数据获得的,这个构造函数从cin中读取数据, //直至遇到文件尾或者遇到一个不是int的数据为止 std::istream_iterator<int> int_iter(std::cin),eof; std::vector<int> vec(int_iter, eof); //#include <fstream>std::ifstream in("file"); std::istream_iterator<std::string> str_it(in); //从in读取字符串
使用算法操作流迭代器
std::istream_iterator<int> int_iter(std::cin), eof; std::cout << std::accumulate(int_iter, eof, 0) << std::endl; //此调用计算从标准输入读取的值之和 //如果输入 125,则输出 8
//使用ostream_iterator来输出值的序列 std::ostream_iterator<int> out_iter(std::cout," "); std::vector<int> vec; for (auto e : vec){ *out_iter++= e; //赋值语句实际上将元素写到cout //运算符++和*对ostream_iterator不做任何事 } std::cout << std::endl; //用out_iter时,可忽略解引用和递增 for (auto e : vec){ out_iter = e; //赋值语句实际上将元素写到cout } std::cout << std::endl; std::copy(vec.begin(), vec.end(), out_iter); std::cout << std::endl;
使用迭代器处理类类型
反向迭代器
反向迭代器需要递减运算符,所以 forward_list 或流迭代器不能创建反向迭代器
std::vector<int> vec = { 0, 1, 2, 3, 4 }; //从尾元素到首元素的方向迭代器 for (auto r_iter = vec.crbegin(); r_iter != vec.crend(); ++r_iter){ std::cout << *r_iter << std::endl; } std::sort(vec.begin(), vec.end()); //正常序列,升序 std::sort(vec.rbegin(), vec.rend()); //逆序排序
std::string line ="first,middle,last"; //在逗号分隔的列表中查找第一个元素 auto comma = std::find(line.cbegin(), line.cend(), ','); std::cout << std::string(line.cbegin(), comma) << std::endl; //在第一逗号分隔的列表中查找最后一个元素 auto rcomma = std::find(line.crbegin(), line.crend(), ','); //错误,将逆序输出单词的字符 std::cout << std::string(line.crbegin(), rcomma) << std::endl; //正确 : 将得到一个正向迭代器,从逗号开始读取字符直至line末尾 std::cout << std::string(rcomma.base, line.cend()) << std::endl;
10.5 泛型算法结构
算法最基本的特性是它要求迭代器提供哪些操作
类似容器,迭代器的操作也是有层次的,高层类别的迭代器支持所有底层类别迭代器操作,例如:
ostream_iterator 只支持递增,解引用和赋值
vector,string,deque 的迭代器还支持递减,关系和算术运算
C++ 标准指明了算法的每个迭代器参数的最小类别:例如,replace_copy 的前两个迭代器至少是向前迭代器,第三个至少是输出迭代器
算法形参模式
大多数算法具有如下四种形式之一 :
算法命名和重载规范
10.6 特定容器算法
对于 list 和 forward_list ,应该优先使用成员函数版本的算法,而不是通用算法