龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

STL组件之迭代器(1)(5)

时间:2011-04-12 23:18来源:未知 作者:admin 点击:
分享到:
前推迭代器 前推迭代器能够读写数据值,并能够向前推进到下一个值。但是没法递减。replace()算法显示了前推迭代器的使用方法。 template class ForwardItera

前推迭代器

前推迭代器能够读写数据值,并能够向前推进到下一个值。但是没法递减。replace()算法显示了前推迭代器的使用方法。

  1. template <class ForwardIterator, class T>  
  2. void replace (ForwardIterator first,  
  3. ForwardIterator last,  
  4. const T& old_value,  
  5. const T& new_value); 

使用replace()将[first,last]范围内的所有值为old_value的对象替换为new_value。:

  1. replace(vdouble.begin(), vdouble.end(), 1.5, 3.14159); 

双向迭代器

双向迭代器要求能够增减。如reverse()算法要求两个双向迭代器作为参数:

  1. template <class BidirectionalIterator>  
  2. void reverse (BidirectionalIterator first,  
  3. BidirectionalIterator last); 

使用reverse()函数来对容器进行逆向排序:

  1. reverse(vdouble.begin(), vdouble.end()); 

随机访问迭代器

随机访问迭代器能够以任意顺序访问数据,并能用于读写数据(不是const的C++指针也是随机访问迭代器)。STL的排序和搜索函数使用随机访问迭代器。随机访问迭代器可以使用关系操作符作比较。

random_shuffle() 函数随机打乱原先的顺序。申明为:

  1. template <class RandomAccessIterator>  
  2. void random_shuffle (RandomAccessIterator first,  
  3. RandomAccessIterator last); 

使用方法:

  1. random_shuffle(vdouble.begin(), vdouble.end()); 

迭代器技术

要学会使用迭代器和容器以及算法,需要学习下面的新技术。

流和迭代器

本书的很多例子程序使用I/O流语句来读写数据。例如:

  1. int value;  
  2. cout << "Enter value: ";  
  3. cin >> value;  
  4. cout << "You entered " << value << endl; 

对于迭代器,有另一种方法使用流和标准函数。理解的要点是将输入/输出流作为容器看待。因此,任何接受迭代器参数的算法都可以和流一起工作。

Listing 4. outstrm.cpp

  1. #include <iostream.h>  
  2. #include <stdlib.h> // Need random(), srandom()  
  3. #include <time.h> // Need time()  
  4. #include <algorithm> // Need sort(), copy()  
  5. #include <vector> // Need vector  
  6.  
  7. using namespace std;  
  8.  
  9. void Display(vector<int>& v, const char* s);  
  10.  
  11. int main()  
  12. {  
  13. // Seed the random number generator  
  14. srandom( time(NULL) );  
  15.  
  16. // Construct vector and fill with random integer values  
  17. vector<int> collection(10);  
  18. for (int i = 0; i < 10; i++)  
  19. collection[i] = random() % 10000;;  
  20.  
  21. // Display, sort, and redisplay  
  22. Display(collection, "Before sorting");  
  23. sort(collection.begin(), collection.end());  
  24. Display(collection, "After sorting");  
  25. return 0;  
  26. }  
  27.  
  28. // Display label s and contents of integer vector v  
  29. void Display(vector<int>& v, const char* s)  
  30. {  
  31. cout << endl << s << endl;  
  32. copy(v.begin(), v.end(),  
  33. ostream_iterator<int>(cout, "t"));  
  34. cout << endl;  

函数Display()显示了如何使用一个输出流迭代器。下面的语句将容器中的值传输到cout输出流对象中:

  1. copy(v.begin(), v.end(),  
  2. ostream_iterator<int>(cout, "t")); 

第三个参数实例化了ostream_iterator<int>类型,并将它作为copy()函数的输出目标迭代器对象。“t”字符串是作为分隔符。运行结果:

  1. $ g++ outstrm.cpp  
  2. $ ./a.out  
  3. Before sorting  
  4. 677 722 686 238 964 397 251 118 11 312  
  5. After sorting  
  6. 11 118 238 251 312 397 677 686 722 964 

这是STL神奇的一面『确实神奇』。为定义输出流迭代器,STL提供了模板类ostream_iterator。这个类的构造函数有两个参数:一个ostream对象和一个string值。因此可以象下面一样简单地创建一个迭代器对象:

  1. ostream_iterator<int>(cout, "n"

该迭代起可以和任何接受一个输出迭代器的函数一起使用。

插入迭代器

插入迭代器用于将值插入到容器中。它们也叫做适配器,因为它们将容器适配或转化为一个迭代器,并用于copy()这样的算法中。例如,一个程序定义了一个链表和一个矢量容器:

  1. list<double> dList;  
  2. vector<double> dVector; 

通过使用front_inserter迭代器对象,可以只用单个copy()语句就完成将矢量中的对象插入到链表前端的操作:

  1. copy(dVector.begin(), dVector.end(), front_inserter(dList)); 

三种插入迭代器如下:

  •  普通插入器 将对象插入到容器任何对象的前面。
  •  Front inserters 将对象插入到数据集的前面——例如,链表表头。
  •  Back inserters 将对象插入到集合的尾部——例如,矢量的尾部,导致矢量容器扩展。

使用插入迭代器可能导致容器中的其他对象移动位置,因而使得现存的迭代器非法。例如,将一个对象插入到矢量容器将导致其他值移动位置以腾出空间。一般来说,插入到象链表这样的结构中更为有效,因为它们不会导致其他对象移动。

Listing 5. insert.cpp

  1. #include <iostream.h>  
  2. #include <algorithm>  
  3. #include <list>  
  4. using namespace std;  
  5. int iArray[5] = { 1, 2, 3, 4, 5 };  
  6. void Display(list<int>& v, const char* s);  
  7. int main()  
  8. {  
  9. list<int> iList;  
  10. // Copy iArray backwards into iList  
  11. copy(iArray, iArray + 5, front_inserter(iList));  
  12. Display(iList, "Before find and copy");  
  13. // Locate value 3 in iList  
  14. list<int>::iterator p =  
  15. find(iList.begin(), iList.end(), 3);  
  16. // Copy first two iArray values to iList ahead of p  
  17. copy(iArray, iArray + 2, inserter(iList, p));  
  18. Display(iList, "After find and copy");  
  19. return 0;  
  20. }  
  21. void Display(list<int>& a, const char* s)  
  22. {  
  23. cout << s << endl;  
  24. copy(a.begin(), a.end(),  
  25. ostream_iterator<int>(cout, " "));  
  26. cout << endl;  

运行结果如下:

  1. $ g++ insert.cpp  
  2. $ ./a.out  
  3. Before find and copy  
  4. 5 4 3 2 1  
  5. After find and copy  
  6. 5 4 1 2 3 2 1 

可以将front_inserter替换为back_inserter试试。

如果用find()去查找在列表中不存在的值,例如99。由于这时将p设置为past-the-end 值。最后的copy()函数将iArray的值附加到链表的后部。

混合迭代器函数

在涉及到容器和算法的操作中,还有两个迭代器函数非常有用:

  • advance() 按指定的数目增减迭代器。
  • distance() 返回到达一个迭代器所需(递增)操作的数目。

例如:

  1. list<int> iList;  
  2. list<int>::iterator p =  
  3. find(iList.begin(), iList.end(), 2);  
  4. cout << "before: p == " << *p << endl;  
  5. advance(p, 2); // same as p = p + 2;  
  6. cout << "after : p == " << *p << endl;  
  7.  
  8. int k = 0;  
  9. distance(p, iList.end(), k);  
  10. cout << "k == " << k << endl; 

advance()函数接受两个参数。第二个参数是向前推进的数目。对于前推迭代器,该值必须为正,而对于双向迭代器和随机访问迭代器,该值可以为负。

使用 distance()函数来返回到达另一个迭代器所需要的步骤。

注意:distance()函数是迭代的,也就是说,它递增第三个参数。因此,你必须初始化该参数。未初始化该参数几乎注定要失败。

希望通过本文的介绍,能够给你帮助。

精彩图集

赞助商链接