要学会使用迭代器和容器以及算法,需要学习下面的新技术。
一、流和迭代器
本书的很多例子程序使用I/O流语句来读写数据。例如:
1 int value; 2 cout << "Enter value: "; 3 cin >> value; 4 cout << "You entered " << value << endl;
对于迭代器,有另一种方法使用流和标准函数。理解的要点是将输入/输出流作为容器看待。因此,任何接受迭代器参数的算法都可以和流一起工作。
1 //outstrm.cpp 2 #include <iostream> 3 #include <cstdlib> // Need rand(), srand() 4 #include <ctime> // Need time() 5 #include <algorithm> // Need sort(), copy() 6 #include <vector> // Need vector 7 #include <iterator> // 坑爹的教程!!,Need for ostream_iterator 8 using namespace std; 9 10 void Display(vector<int>& v, const char* s); 11 12 int main() 13 { 14 // Seed the random number generator 15 srand( time(NULL) ); 16 17 // Construct vector and fill with random integer values 18 vector<int> collection(10); 19 20 for (int i = 0; i < 10; i++) 21 { 22 collection[i] = rand() % 10000; 23 } 24 25 // Display, sort, and redisplay 26 Display(collection, "Before sorting"); 27 sort(collection.begin(), collection.end()); 28 Display(collection, "After sorting"); 29 return 0; 30 } 31 32 // Display label s and contents of integer vector v 33 void Display(vector<int>& v, const char* s) 34 { 35 cout << endl << s << endl; 36 copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); 37 cout << endl; 38 }
函数Display()显示了如何使用一个输出流迭代器。下面的语句将容器中的值传输到cout输出流对象中:
copy(v.begin(), v.end(),ostream_iterator<int>(cout, " "));
第三个参数实例化了ostream_iterator<int>类型,并将它作为copy()函数的输出目标迭代器对象。“ ”字符串是作为分隔符。
这是STL神奇的一面『确实神奇』。为定义输出流迭代器,STL提供了模板类ostream_iterator。这个类的构造函数有两个参数:一个ostream对象和一个string值。
因此可以象下面一样简单地创建一个迭代器对象:
ostream_iterator<int>(cout, " ")
该迭代器可以和任何接受一个输出迭代器的函数一起使用。
二、插入迭代器
插入迭代器用于将值插入到容器中。它们也叫做适配器,因为它们将容器适配或转化为一个迭代器,并用于copy()这样的算法中。例如,一个程序定义了一个链表和一个矢量容器:
list<double> dList;
vector<double> dVector;
通过使用front_inserter迭代器对象,可以只用单个copy()语句就完成将矢量中的对象插入到链表前端的操作:
copy(dVector.begin(), dVector.end(), front_inserter(dList));
三种插入迭代器如下:
- inserter 将对象插入到容器任何对象的前面。
- front_inserter 将对象插入到数据集的前面——例如,链表表头。
- back_inserter 将对象插入到集合的尾部——例如,矢量的尾部,导致矢量容器扩展。
使用插入迭代器可能导致容器中的其他对象移动位置,因而使得现存的迭代器非法。例如,将一个对象插入到矢量容器将导致其他值移动位置以腾出空间。一般来说,插入到象链表这样的结构中更为有效,因为它们不会导致其他对象移动。
1 #include <iostream> 2 #include <algorithm> 3 #include <list> 4 #include <iterator> 5 6 using namespace std; 7 8 int iArray[5] = { 1, 2, 3, 4, 5 }; 9 10 void Display(list<int>& v, const char* s); 11 12 int main() 13 { 14 list<int> iList; 15 16 // Copy iArray backwards into iList 17 18 copy(iArray, iArray + 5, front_inserter(iList)); //5 4 3 2 1 19 //copy(iArray, iArray + 5, inserter(iList, iList.begin())); //1 2 3 4 5 20 //copy(iArray, iArray + 5, back_inserter(iList)); //1 2 3 4 5 21 22 Display(iList, "Before find and copy"); 23 24 // Locate value 3 in iList 25 list<int>::iterator p = find(iList.begin(), iList.end(), 3); 26 27 // Copy first two iArray values to iList ahead of p 28 copy(iArray, iArray + 2, inserter(iList, p)); //插入1 2到3的前面 29 Display(iList, "After find and copy"); 30 31 return 0; 32 } 33 34 void Display(list<int>& a, const char* s) 35 { 36 cout << s << endl; 37 copy(a.begin(), a.end(), ostream_iterator<int>(cout, " ")); 38 cout << endl; 39 }
使用front_inserter插入到链表的前端的时候,数据会倒过来- -
使用普通插入器inserter指定插入到链表前端和使用back_inserter数据都是按照原顺序输出的。。
三、混合迭代器函数
在涉及到容器和算法的操作中,还有两个迭代器函数非常有用:
- advance() 按指定的数目增减迭代器。
- distance() 返回到达一个迭代器所需(递增)操作的数目。
1 #include <iostream> 2 #include <algorithm> 3 #include <list> 4 using namespace std; 5 6 int iArray[5] = { 1, 2, 3, 4, 5 }; 7 8 int main() 9 { 10 list<int> iList; 11 12 copy(iArray, iArray + 5, inserter(iList, iList.begin())); //1 2 3 4 5 13 14 list<int>::iterator p =find(iList.begin(), iList.end(), 2); 15 16 cout << "before: p == " << *p << endl; 17 advance(p, 3); // same as p = p + 2; 向后移动3位 18 cout << "after : p == " << *p << endl; 19 20 int k = distance(p, iList.end()); //起始位置在前,终止位置在后 21 cout << "k == " << k << endl; 22 23 k = distance(p, iList.begin()); //2 STL中list是双向循环链表 24 cout << "k == " << k << endl; 25 26 k = distance(iList.begin(), p); //4 27 cout << "k == " << k << endl; 28 29 //begin指向第一个位置,end指向最后一个位置的后一个位置 30 //cout << *iList.begin() << endl; 31 //cout << *iList.end() << endl; 32 return 0; 33 }
advance()函数接受两个参数。第二个参数是向前推进的数目。对于前推迭代器,该值必须为正,而对于双向迭代器和随机访问迭代器,该值可以为负。
(这不是往后推进的吗?呃。。。不知道作者有没有搞错- -以上是作者原话)
使用 distance()函数来返回到达另一个迭代器所需要的步骤。
前者到后者的步数