【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
以下内容大多来自《C++标准程序库》
迭代器是一个“可遍历STL容器内全部或部分元素”的对象,一个迭代器用来指出容器中的一个特定位置。
基本操作:
(1)Operator * :返回当前位置上的元素值
(2)Operator ++:将迭代器前进至下一个元素,大多数迭代器还可以使用operator -- 退回到前一个元素
(3)Operator ==和Operator != 判断两个迭代器是否指向同一个位置
(4)Operator = 为迭代器赋值
这些操作与操作数组元素时的指针接口是一致的,不同在于迭代器具有遍历复杂数据结构的能力,其下层运行机制取决于其所遍历的数据结构,因此,每一种容器型别都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套方式定义于内部,因此各种迭代器的接口相同,型别却不相同。
重要函数
所有容器类别都提供有一些成员函数,使我们得以获得迭代器并一直遍访所有元素。
begin()
返回一个迭代器,指向容器起始点的位置
end()
返回一个迭代器,指向容器结束点。结束点在最后一个元素之后,这样的迭代器又称作逾尾(past-the-end)迭代器(所以遍历的时候都是判断!=end())
#include <iostream> #include <list> using namespace std; int main() { list<char>coll; for (char c = 'a'; c <= 'z'; ++c) { coll.push_back(c); } /* while (!coll.empty()) { //这个也可以显示出来,不过元素都出去了, 所以List空了,程序没有进入迭代器(或者说begin=end了)就结束了 cout << coll.front() << ' '; coll.pop_front(); } */ list<char>::const_iterator pos; //迭代器声明于循环之前 (这个不是定义吗?书上写的是声明。。) for (pos = coll.begin(); pos != coll.end(); ++pos) { cout << *pos << ' '; //*pos代表当前元素 } cout << endl; system("pause"); }
在网上看到了另外一种迭代器写法:
for (auto pos = coll.begin(); pos != coll.end(); ++pos) { //以后多用前置式递增,它比后置式递增pos++效率要高,而且可能更加符合人们本来的意思 cout << *pos << ' '; }
这样就可以不用声明了
两种迭代器型别:
container::iterator
这种迭代器以“读/写”模式遍历元素
container::const_iterator
这种迭代器以“只读”模式遍历元素
迭代器分类
1.双向迭代器
该迭代器可以双向行进,以递增运算前进,或以递减运算后腿,list/map/multimap/set/multiset这些容器提供的迭代器都属于此类;
2.随机存取迭代器
该迭代器不但具备双向迭代器的所有属性,还具备随机访问能力,可以对迭代器减少或增加一个迁移量、处理迭代器之间的距离或者使用<或>之类的相对关系操作符来比较两个迭代器。vector/deque/strings提供的迭代器都属于此类
比较以下两者
for (auto pos = coll.begin(); pos != coll.end(); ++pos) { cout << *pos << ' '; } for (auto pos = coll.begin(); pos < coll.end(); ++pos) { cout << *pos << ' '; }
其不同在于测试循环的条件,因为只有随机存取迭代器才支持operator<,所以如果用第二种,则list /set / map无法运作,因此我们最好还是使用第一种迭代方式
匹配器(特殊的迭代器):
1.安插型匹配器(Insert iterators)
Inserters可以使算法以安插的方式而非赋写的方式运作。使用它可以解决目标空间不足的问题,它会促使目标区间的大小俺需要成长。
#include <iostream> #include <vector> #include <list> #include <deque> #include <set> #include <algorithm> #include <iterator> using namespace std; int main() { list<int>coll1; for (int i = 1; i <= 9; ++i) { coll1.push_back(i); } vector<int>coll2; copy(coll1.begin(),coll1.end(),back_inserter(coll2)); for (auto pos = coll2.begin(); pos != coll2.end(); ++pos) { cout << *pos << " "; } cout << endl; deque<int>coll3; copy(coll1.begin(), coll1.end(), front_inserter(coll3)); for (auto pos = coll3.begin(); pos != coll3.end(); ++pos) { cout << *pos << " "; } cout << endl; set<int>coll4; copy(coll1.begin(), coll1.end(), inserter(coll4,coll4.begin())); for (auto pos = coll4.begin(); pos != coll4.end(); ++pos) { cout << *pos << " "; } system("pause"); }
结果:
1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9
这里刚开始报了一个错误:error C3861: back_inserter : 找不到标识符,查找了一下应该是VC版本更迭出现的问题,需要在头部声明#include <iterator>来解决。
这个例子用了三种预先定义的insert iterators:
1.Back inserters
其内部调用了push_back(),从尾端插入元素(从尾部进,从头部出,所以是正着的)
当然Back inserters只有在提供有push_back()成员函数的容器中才能派上用场,即只能用在vectoe,deque,list(序列式容器)
2.Front inserters
其内部调用了front_back(),这种动作会逆转被安插的元素次序(从头部插入,又从头部出,所以后进的先出了,所以反了)
Front inserters只有在提供有front_back()成员函数的容器中才能派上用场,即只能用在deque,list
3.General inserters
可用户所有容器,也是唯一可用于关联式容器的inserter。
比如对第三个coll4进行了如下更改:
coll1.push_back(3); cout << endl; multiset<int>coll4; copy(coll1.begin(), coll1.end(), inserter(coll4,coll4.begin())); for (auto pos = coll4.begin(); pos != coll4.end(); ++pos) { cout << *pos << " "; }
虽然coll的在尾部加了一个值为3的元素,但是输出仍然是排好序的1 2 3 3 4 5 6 7 8 9
2.流迭代器(Stream Iterators)
流迭代器是一种用来读写stream的迭代器,使得来自键盘的输入像是一个集群,能够从中读取内容,同理也可以把算法输出结果重新导向到某个文件或者屏幕上。
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <iterator> using namespace std; int main() { vector<string>coll; copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(coll));//从屏幕读取输入的文字 sort(coll.begin(), coll.end());//排序 unique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout,"\n"));//打印到屏幕 system("pause"); } 结果:或者要对比数字的话可以把上的的string改成int : 1 2 3 4 5 6 8 10 5 9 4 7 3 ^Z //这里注意,采用了空行+ctrl+z的方式才能结束输入程序 1 2 3 4 5 6 7 8 9 10
1.istream_iterotor<string>(cin)
从标准输入流cin读取数据的istream iterator,每当算法企图处理下一个元素时,istream iterator就会将这种企图转化为cin>>string;
2.istream_iterotor<string>()
调用istream iterators的默认构造函数,产生一个代表“流结束符号”的迭代器,作为区间终点,在网上找的要用ctrl+c来结束
3. unique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout,"\n"));
将其中所有元素拷贝到目标端cout,处理过程中算法unique_copy会消除重复值
其中ostream_iterator<string>(cout,"\n")会产生一个output stream iterator通过operator<<向cout写入strings,cout之后的第二个参数(可以省略)被用来作为元素间的分隔符
3.逆向迭代器(reverse iterators)
以逆向方式进行所有操作。它将递增运算转换成递减运算,反之亦然,所有容器都可以通过成员函数rbegin()和rend()产生reverse iterators
#include <iostream> #include <vector> #include <list> #include <deque> #include <set> #include <algorithm> #include <iterator> using namespace std; int main() { vector<int>coll; for (int i = 1; i <= 9; ++i) { coll.push_back(i); } copy(coll.rbegin(), coll.rend(), ostream_iterator<int>(cout," ")); cout << endl; system("pause"); }
结果为:
9 8 7 6 5 4 3 2 1
1.coll.rbegin()
指向集群的结尾位置(书上说是最后元素的下一个位置,我觉得不对)
cout << *coll.rbegin() << endl; cout << *coll.rend() << endl;
通过这个来测试,第一个输出的是9,也就是最后一个位置
2.coll.rend()
指向容器内第一个元素的前一个元素
因此上面那个测试第二个是无法输出的,程序终止了。并且注意,*coll.rend()与*coll.end()没有定义,当某个位置上并无合法元素时,永远不要用opterator*或者opterator->
来源:oschina
链接:https://my.oschina.net/u/4433424/blog/3153577