当前课程知识点:C++语言程序设计进阶 > 第十章 泛型程序设计与C++标准模板库 > 迭代器 > 迭代器
迭代器是算法和容器的桥梁
迭代器用作访问容器中的元素
算法不直接操作容器中的数据,而是通过迭代器间接操作
算法和容器独立
增加新的算法,无需影响容器的实现
增加新的容器,原有的算法也能适用
输入流迭代器
istream_iterator<T>
以输入流(如cin)为参数构造
可用*(p++)获得下一个输入的元素
输出流迭代器
ostream_iterator<T>
构造时需要提供输出流(如cout)
可用(*p++) = x将x输出到输出流
二者都属于适配器
适配器是用来为已有对象提供新的接口的对象
输入流适配器和输出流适配器为流对象提供了迭代器的接口
//10_2.cpp #include <iterator> #include <iostream> #include <algorithm> using namespace std; //求平方的函数 double square(double x) { return x * x; } int main() { //从标准输入读入若干个实数,分别将它们的平方输出 transform(istream_iterator<double>(cin), istream_iterator<double>(), ostream_iterator<double>(cout, "\t"), square); cout << endl; return 0; }
迭代器是泛化的指针,提供了类似指针的操作(诸如++、*、->运算符)
输入迭代器
可以用来从序列中读取数据,如输入流迭代器
输出迭代器
允许向序列中写入数据,如输出流迭代器
前向迭代器
既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
双向迭代器
与前向迭代器相似,但是在两个方向上都可以对数据遍历
随机访问迭代器
也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转,如指针、使用vector的begin()、end()函数得到的迭代器
两个迭代器表示一个区间:[p1, p2)
STL算法常以迭代器的区间作为输入,传递输入数据
合法的区间
p1经过n次(n > 0)自增(++)操作后满足p1 == p2
区间包含p1,但不包含p2
程序涉及到输入迭代器、输出迭代器、随机访问迭代器这三个迭代器概念,并且以前两个概念为基础编写了一个通用算法。
//10_3.cpp #include <algorithm> #include <iterator> #include <vector> #include <iostream> using namespace std; //将来自输入迭代器的n个T类型的数值排序,将结果通过输出迭代器result输出 template <class T, class InputIterator, class OutputIterator> void mySort(InputIterator first, InputIterator last, OutputIterator result) { //通过输入迭代器将输入数据存入向量容器s中 vector<T> s; for (;first != last; ++first) s.push_back(*first); //对s进行排序,sort函数的参数必须是随机访问迭代器 sort(s.begin(), s.end()); copy(s.begin(), s.end(), result); //将s序列通过输出迭代器输出 } int main() { //将s数组的内容排序后输出 double a[5] = { 1.2, 2.4, 0.8, 3.3, 3.2 }; mySort<double>(a, a + 5, ostream_iterator<double>(cout, " ")); cout << endl; //从标准输入读入若干个整数,将排序后的结果输出 mySort<int>(istream_iterator<int>(cin), istream_iterator<int>(), ostream_iterator<int>(cout, " ")); cout << endl; return 0; } /* 运行结果: 0.8 1.2 2.4 3.2 3.3 2 -4 5 8 -1 3 6 -5 -5 -4 -1 2 3 5 6 8 */
advance(p, n)
对p执行n次自增操作
distance(first, last)
计算两个迭代器first和last的距离,即对first执行多少次“++”操作后能够使得first == last
大家好
欢迎回来继续学习
C++语言程序设计
这一节我们来学习迭代器
迭代器是算法和容器之间的桥梁
因为有这个桥梁
算法和容器彼此就可以独立
程序就可以更为通用
迭代器是用来作为
迭代容器中的元素用的
也就是说
我们可以用迭代器
就能依次访问容器中的元素
这样算法就不直接操作
容器中的数据了
而是通过迭代器
来间接操作
由于算法和容器
它们彼此独立
这样的话
增加新的算法
就不会影响原来容器的实现
增加新的容器呢
原有的所有算法
也依然能够适用
首先我们来看
输入流迭代器和输出流迭代器
输入流迭代器呢
是用于输入数据的
比如说我们可以用cin作为参数
去构造一个输入流迭代器
那么这个输入流迭代器呢
就可以用于从标准设备输入数据
那么怎么用输入流迭代器
输入数据呢
比如说
我们用指针运算就可以
获得下一个输入的元素
就像指针操作一样 非常方便
同样 输出流迭代器
也是为了输出用的
比如说如果我们用cout
去构造一个输出流迭代器的话
我们就可以用这个迭代器
将数据送到标准输出设备去
这里 举了一个例子
如果我们对输出流迭代器
进行指针运算
然后再给它赋值
这就相当于
将赋给它的这个x
送到输出流中去了
那为了数据能够持续地输入
持续地输出
我们可以在进行指针运算的时候
同时进行自增运算
这样就可以不断地获取
下一个元素
不断地把数据送到输出设备去
这两个迭代器呢
实际上都属于适配器
那么适配器是什么呢
适配器是用来为已有的对象
提供新的接口的这样的对象
输入流适配器和输出流适配器
都是为流对象
提供了迭代器的接口
下面一个例子呢
将从标准输入设备
输入几个实数
计算他们的平方
然后依次输出到标准输出设备去
通过这个例子
我们可以再次地看到
怎么样使用这个transform
怎么样传递函数对象
那么最重要的是
如何通过输入流迭代器
从键盘输入数据
然后通过输出流迭代器
将运算结果输出到显示器去
在这个程序中
我们自己写了一个求平方的函数
square
那用这个函数作为
transform算法所需要的函数对象
传给它
大家看在这儿
作为函数对象参数
那也就是说呢
我们要对读入的数据
每一个数据依次
进行求平方的计算
然后数据从哪里读入呢
看这个输入流迭代器
这是用cin作为参数
构造的一个输入流迭代器
它的类型参数是double
也就是要从键盘
标准输入设备读入double数据
那么读入到什么地方
算是流结束呢
第二个输入流迭代器
是用默认方式构造的
它就表示输入流的结束位置
这样执行的时候
就会依次从键盘读入各个实数
double数据
直到输入流的结束位置为止
所以执行的时候呢
要给它一个输入流结束的标记
在windows系统里面
我们需要介入ctrl z
在linux系统里面呢
我们需要介入ctrl d
然后所有的数据
依次从输入流读入
直到流结束为止
每一个数据读入以后
要用square对它进行计算
就是求平方了
然后计算结果呢
要依次送到
这个输出流迭代器
指示的输出流里面去
这个输出流呢
它的构造参数
我们用到了cout
就表示是标准输出设备
通常是显示器
这第二个参数呢
表示输出数据
它显示的时候的分隔符
这里我们指定是用tab作为分隔符
这样通过这个transform算法呢
就依次读入了若干实数
并且求平方 然后输出了
这个图
简要地表示了迭代器的分类
我们看到有输入迭代器
输出迭代器
前向迭代器 双向迭代器
和随机访问迭代器
在后面的例子中呢
我们会使用到
其中的一些迭代器的种类
大家会通过例题了解
它们是怎么工作的
迭代器是泛型的指针
它提供了类似于指针的操作
现在我们来看看
迭代器到底支持哪些操作呢
输入迭代器
可以用来从序列中读取数据
比如说输入流迭代器就是这样
输出迭代器呢
允许向序列中写入数据
比如输出流迭代器
那前向迭代器
既是输入迭代器
又是输出迭代器
并且还可以对序列
进行单向的遍历
双向迭代器呢
与前向迭代器相似
但是在两个方向上
都可以对数据进行遍历
随机访问迭代器
它同时也是双向迭代器
除此而外
它还能够在序列中的
任何两个位置之间进行跳转
比如说指针
使用vector的begin end函数
得到的迭代器
都是随机访问迭代器
我们可以用两个迭代器
来表示一个区间
左边是闭区间 右边是开区间
STL算法
通常都是以迭代器区间
作为输入的
用迭代器来传递数据
合法的区间呢 是p1
也就是起始位置的迭代器
经过n次自增操作以后
当满足p1等于p2以后
那么就结束了
所以我们的算法中呢
经常是用这样的方式
来控制循环
这个区间包括p1
但是不包括p2
也就是说
迭代器p2是指向
要处理的数据区间
之后的下一个位置的
接下来呢
我们来看一个
综合运用几种迭代器的程序实例
程序中涉及到了
输入迭代器 输出迭代器
随机访问迭代器
这三个迭代器的概念
并且还用前两个迭代器的概念
作为基础
编写了一个通用的算法
这里我们基于迭代器的概念
自己编写了一个mySort
排序函数模板
它的三个参数呢
分别是两个输入迭代器
和一个输出迭代器
输入迭代器first和last
指示了
需要处理的数据的开始位置
first是它开始位置
还有呢
需要处理的那个数据序列的
最后一个元素之后的位置
就是last
然后result指示了处理的结果
也就是排序的结果
将输出到哪里去
首先通过输入迭代器
将first到last范围之间的数据
存入到向量容器s里面
我们看到在for循环中呢
是用first和last来控制循环的
每一次从这个输入序列
也就是要处理的
这个需要排序的这个序列的里面
依次取出一个元素来
存入s里面
也就是向量容器里面
然后这个输入迭代器
会依次前进一个元素的位置
直到全部的序列处理完
就是first达到last指示的位置了
就是全部的序列里面的数据
都已经存入到s里面了
现在我们再将s里面的数据
需要排序的数据区间
传给这个sort函数
sort函数
它的参数必须是
随机访问的迭代器
那么这里我们给它的是
s这个容器它的begin和end
这两个迭代器
由begin函数和end函数
分别返回一个迭代器
指向这个数据序列的开始位置
和指向它的结束位置
这样呢
我们就用sort对s里面的数据
进行了排序
排序以后的数据呢
我们要用copy函数
送到result迭代器
指示的输出位置去
那么这个输出的序列
需要输出的序列
也是由s.begin返回的迭代器
指示它的开始位置
由s.end返回迭代器
指示它的结束位置
然后copy的目的地是
result迭代器指示的位置
也就是送到输出的地方去
接下来我们来看主函数中
定义了一个double类型的数组a
然后我们就将a的起始位置
也就是数组名
还有a的结束位置
也就是a的全部五个元素
之后的那个位置
这两个位置呢
作为迭代器的实参
输入迭代器的实参
传给mySort
那么排序以后的内容
需要送到哪儿去呢
需要送到标准输出流
所以我们构造了一个
输出流迭代器
用cout作参数
然后输出的数据间隔是空格
这样传给mySort
这样执行了mySort以后呢
排序以后的数据
就送到了显示器上
我们看到第一行输出结果
这是定义的a数组里面的元素
都经过排序了 输出了
那接下来呢
我们再次调用mySort
这回是从标准输入设备
也就是从标准输入流
读入若干个整数
然后将排序以后的结果呢
还是输出到标准输出
现在我们再来看
实参的给的是什么
第一个输入迭代器给的是
标准输入流
第二个
是给的标准输入流的结束位置
这样的话
就会依次从键盘读入数据
我们从键盘输入这样一行数据
然后将排序以后的结果
送到标准输出流去
并且以空格分割
所以我们看到
从键盘输入的数据呢
现在排序以后输出了
迭代器还附有一些辅助函数
比如说 这个advance函数
就可以使
迭代器连续执行多次自增操作
比如说advance函数
它有两个参数
第一参数它是迭代器
第二个参数是一个整数
它的意思就是
对p执行n次自增操作
distance呢
它的参数是两个迭代器参数
first和last
它的作用是计算两个迭代器
之间的距离
也就是说
要对first执行多少次自增操作
才能够使first与last相等
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义