C++学习之迭代器
来源:互联网 发布:三菱plc编程实例精解 编辑:程序博客网 时间:2024/06/14 15:22
C++标准库中的3个重要概念就是容器,迭代器,算法,标准库中的常用容器有vector,list,deque,map,set,multimap,multiset(C++11中新增了array,forward_list,unordered_map,unordered_set,unordered_multimap,unordered_multiset),这些容器大家都经常用到,相对比较熟悉。但是使用C++,就必须得熟悉其提供给我们的100多个泛型算法(参见C++学习之标准库泛型算法_STL算法),这样我们就可以避免重复造轮子。泛型算法不是调用容器已有的操作实现,而是借助于迭代器来实现,所以调用泛型算法的时候,我们需要传递迭代器参数来指明输入范围和输出范围,所以在学习泛型算法之前,必须先了解迭代器的概念,类型等。
下面是我在看了C++primer第11章泛型算法后自己的理解:
一、什么是迭代器?
我的理解是迭代器提供了一种遍历容器内元素的方法,比如遍历数组可以通过指针实现,指针就可以认为是一种迭代器,可以参见C++ Primer的p84 。
我认为迭代器没有责任去检测越界,比如当某个迭代器位于超出末端下一位置,如果再对它进行自增运算,那么就会出现运行时错误:“iterator not incrementable"。
二、迭代器种类
1.从迭代器的类型上对迭代器分类
(1)普通迭代器:就是我们经常使用的 容器::iterator,比如std::vector<int>::iterator,一般都支持++、--操作,其他算术操作看具体的容器类型;
(2)反向迭代器:这一种迭代器也是经常用到的,比如std::list<int>::reverse_iterator,一般都支持++、--操作,其他算术操作看具体的容器类型;
反向迭代器的通过使用普通迭代器的自减操作实现的,所以从一个支持--同时也支持++的迭代器就可以定义反向迭代器
*上面两种类型的迭代器都有相应的const迭代器,const迭代器不能修改其指向的元素,比如std::list<int>::const_iterator,std::list<int>::const_reverse_iterator,const迭 代器类似于const int* p。
(3)流迭代器:输入输出流不是容器,但是标准库将它看作了”容器“,流迭代器只支持向前遍历(++)这是流的特点决定的,因此流迭代器不能创建反向迭代器。流迭代器分为了istream_iterator和ostream_iterator,分别用于遍历输入、输出流,并且我们只能从istream_iterator读入输入流的内容,通过ostream_iterator写出到输出流。
istream_iterator提供的操作
it1==it2 比较两个迭代器是否相同。
it1!=it2 如果两个都指向end,那么it1==it2;如果均不指向end,且由同一个输入流构造,那么也相等。
比较运算符必须是 读取相同类型的两个流迭代器
*it 返回从流中读取的值,作为右值使用
it->v 或 (*it).v 返回读取对象的成员v
++it
it++
ostream_iterator 只提供*it (作为左值使用),++it ,it ++,不提供比较和成员选择操作。
流迭代器的构造函数
istream_iterator<T> in(stream) 创建从输入流stream读入T类型对象的 istream_iterator对象
istream_iterator<T> in istream_iterator对象的超出末端迭代器
ostream_iterator<T> out(stream) 创建将T类型对象写出到输出流stream的ostream_iterator对象,可以指名输出时的分隔符,如下
ostream_iterator<T> out(stream,delim)
*ostream_iterator 不提供比较函数,所以就没必要定义其对应的超出末端的迭代器了
任何定义了输入操作符(>>)的类型都能定义都可以定义 istream_iterator,同时任何定义了输出操作符(<<)的类型都能定义都可以定义 ostream_iterator
下面是流迭代器的例子
//将input.txt 内容拷贝到output.txt,以换行符分隔输出ifstream fileIn("input.txt");istream_iterator<string> iit(fileIn);istream_iterator<string> eof;ofstream fileOut("output.txt");ostream_iterator<string>oit(fileOut,"\n");copy(iit,eof,oit);fileOut.clear();fileOut.close();fileIn.clear();fileIn.close();
(4)插入迭代器:插入迭代器实际是迭代器适配器,它又分为了首插入迭代器、尾插入迭代器、指定位置插入迭代器,即front_inserter,back_inserter,inserter.
适配器的概念可以参见http://kingphp.blog.163.com/blog/static/200423244201272953254508/,这里插入适配器,带有一个容器形参,并生成一个在此容器上的一个迭代器,用于向容器中插入元素,首插入迭代器、尾插入迭代器、指定位置插入迭代器的位置分别是容器首部、超出末端第一个位置、指定位置,(C++STL插入的意思是在指定位置前添加元素),并且在多次使用某个插入迭代器的时候,其位置永远是容器首部、尾部、指定的位置。比如下面的代码:
#include<iostream>#include<iterator>#include<list>#include<algorithm>int main(int argc,char**argv){std::list<int> vInt1,vInt2;for(int i=0;i<5;++i){vInt1.push_back(i);vInt2.push_back(i+5);}//vInt1 0,1,2,3,4//vInt2 5,6,7,8,9//使用inserter vInt1 copy到 vInt2的7的前面//结果 5 6 0 1 2 3 4 7 8 9std::copy(vInt1.begin(),vInt1.end(),std::inserter(vInt2,std::find(vInt2.begin(),vInt2.end(),7)));for(std::list<int>::iterator it=vInt2.begin();it!=vInt2.end();++it)std::cout<<*it<<" ";std::cout<<std::endl;//使用front_inserter vInt1 copy到 vInt2 前面//结果 4 3 2 1 0 5 6 0 1 2 3 4 7 8 9std::copy(vInt1.begin(),vInt1.end(),std::front_inserter(vInt2));for(std::list<int>::iterator it=vInt2.begin();it!=vInt2.end();++it)std::cout<<*it<<" ";std::cout<<std::endl;return EXIT_SUCCESS;}
值得注意的是front_inserter,back_inserter,inserter分别调应其参数类型容器的push_front,push_back,insert操作,所以得要求容器具有相应的操作才行,比如不能在vector上构造front_inserter。
2.通过STL中泛型算法对迭代器参数类型的要求对迭代器分类
(1)输入迭代器 只读(一次),不写,支持自增 ,如istream_iterator
(2)输出迭代器 只写(一次),不读,支持自增,如ostream_iterator
(3)前向迭代器 支持同一元素的多次读写
(4)双向迭代器 从两个方向读写,如list<t>::iterator
(5)随机访问迭代器 在常量时间内读写任意位置, vector,deque,string可以提供,常用的指针也是。
这几种迭代器具有层次结构(具体层次结构请参见C++学习之深入理解迭代器),下层具有上层的功能,并且添加了添加一些额外的操作,如下图。
注意:所有标准库提供的迭代器都至少达到双向迭代器的要求;
由于关联容器map,set的键是const类型,不能写入,所以将关联容器的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器;
算法中用于标记范围的一对迭代器必须是同种类型。
- .net学习之c#
- 学习笔记之c
- C学习之路
- Unity3D之C#学习
- C学习之------C函数指针
- C语言学习之extern "C"
- c语言学习之c语言概述
- C++、C++学习之我见
- C++、C++学习之我见
- C语言学习之路
- C++、C++学习之我见
- C#.NET学习之路
- c++DLL 学习之路
- C/C++ 学习之路
- C++STL之map学习
- C语言学习之路。
- c++DLL 学习之路
- C语言学习之变量
- 模仿美丽说浮动导航
- cpp关于const和函数
- AES加密CBC模式兼容互通四种编程语言平台【PHP、Javascript、Java、C#】
- JDBC常见面试题集锦(二)
- Android 导航栏如何支持长按 home 键事件分发
- C++学习之迭代器
- qq登录,新浪微博登录 ,接口开发
- db2命令
- Oracle存储过程本地编译方式
- VB6中使用Winsock穿越各种代理的实现(TCP协议)
- iOS学习之UIDatePicker控件使用
- Oracle Database Installation Requirements Reference (8.0.5 to 11.2) (文档 ID 169706.1)
- [算法]学习算法之路
- 关于建站中CSS调用的问题