C++筆記------叠代器
STL是一種泛型編程。對象編程關註的是編程的數據方面,泛型編程關註的是算法的通用,它們之間的共同點的抽象和創建可重用代碼,但理念不同。
STL使用術語“概念”描述叠代器所需要滿足的一系列要求,如正向叠代器是一種要求,而不是類型。
STL使用術語“改進”來表示這種概念上的繼承,概念具有類似繼承的關系,但不能將C++繼承機制用於叠代器。
概念的具體實現被稱為模型,所以一個指向int的常規指針是一個隨機訪問叠代器的模型,也是一個正向叠代器的模型。
STL首先為每個容器類定義了相應的叠代器類型,叠代器可以是指針,也可以是對象。叠代器都將提供一些基礎操作,如*和++。
其次每個容器類都有超尾標記,通過讓叠代器++操作,從第一個元素逐步指向超尾位置,實行遍歷容器中每一個元素。
STL定義了5種叠代器,分別為輸入叠代器,輸出叠代器,正向叠代器,雙向叠代器和隨機訪問叠代器。這5種叠代器都可以執行解除應用操作,如果兩個叠代器相同,則對它們執行解除引用得到的值也一樣。叠代器的特征和容器的特征是基於算法要求進行設計。
1.輸入叠代器:
(1)“輸入”是指從容器中獲取信息,所以輸入叠代器用來讀取容器中信息,但不能讓程序修改值。
(2)輸入叠代器是單向的,可以使用++運算符進行遞增操作,但不能倒退。
2.輸出叠代器:
(1)“輸出”是指信息從程序中傳輸給容器,所以只能讓程序修改容器的值,但不能讀取。
(2)輸出叠代器也是單向的,可以使用++運算符進行遞增操作,但不能倒退。
Ps:對於單通行,只寫的算法,可以使用輸出叠代器;對於單通行,只讀的算法,可以使用輸入叠代器。
3.正向叠代器:
(1)正向叠代器只使用++運算符來遍歷容器,能按相同的順序進行遍歷。
(2)正向叠代器遞增後,仍可以對前面的叠代器(已經保存的)值進行解除引用操作,可以得到相同的值。
(3)正向叠代器既可以讀取和修改數據,也可以只讀數據。
4.雙向叠代器:
(1)包含所有正向叠代器的特性,支持遞減運算符(a--和--a)。
5.隨機叠代器:
(1)能夠直接跳到容器中任何一個元素,進行隨機訪問,包含了所有雙向叠代器的特性。
Ps:
1.編寫算法時,通過使用最低級別的叠代器,可以增加算法的通用性。例如fing()函數可以用於任何包含可讀取的叠代器的容器。而sort()函數需要隨機訪問叠代器,所以只有支持這種叠代器的容器。
2.各種叠代器的類型並不是確定的,只是一種概念性描述。每個容器類定義一個類級的typedef 名稱-----iterator。
如前所說,叠代器是廣義指針,而指針滿足叠代器所有要求,因此STL算法可以使用對基於指針的非STL容器進行操作。
例如:
C++將超尾概念用於數組,可以將STL的算法用於常規數組。指針也是叠代器,也使得STL算法用於常規數組。
#include <iostream> #include <iterator> #include <algorithm> #include <vector> using namespace std; void output(const int s) { cout << s << " "; } int main() { int casts[10] = { 6,7,2,9,4,11,8,7,10,5 }; std::vector<int> dice(10); //將數據從一種容器復制到另一種容器 //前兩個參數復制範圍,最後一個參數復制到什麽位置。 //目標容器必須足夠大,以便能容納元素 copy(casts, casts + 10, dice.begin()); for (auto x : casts) cout << x << " ";//基於範圍的for循環 cout << endl; ostream_iterator<int, char>out_iter(cout, " "); //適配器——一個類或函數,可以將其它接口轉換成STL使用的接口 //第一個參數:指出發送給輸出流的數據類型 //第二個參數:指出輸出流使用的字符類型(可能是wchar_t) //構造函數的第一個參數:指出使用的輸出流 //第二個參數:輸出流的每個數據項後面顯示的分隔符 copy(dice.begin(), dice.end(), out_iter); cout << endl; *out_iter++ = 15; //將15和空格組成的字符串發送到cout管理的輸出流中 想當於 cout << 15 << " "; cout << endl; //可以直接使用,而不創建命名叠代器 copy(dice.begin(), dice.end(), ostream_iterator<int, char>(cout, " ")); std::vector<int> dice1(10); vector<int> ::iterator rp; for (rp = dice1.begin(); rp != dice1.end(); rp++) cin >> *rp; for_each(dice1.begin(), dice1.end(), output); cout << endl; vector<int>::reverse_iterator ri; //對 revere_iterator執行遞增操作會導致它自減 //rbegin() and end() 返回值一樣,但類型不一樣(reverse_iterator and iterator) //rend() and begin() 返回值一樣,類型不一樣,都返回指向第一元素的地址 //在對ri進行解除引用之前,先自減,在解除引用。例如:ri執行位置6,*ri是位置5的數值 for (ri = dice1.rbegin(); ri != dice1.rend(); ++ri) cout << *ri << " "; cout << endl; return 0; }
Ps:
1.為什麽ri需要先自減?
因為rbegin()返回超尾,所以不能進行解除引用,同理rend()返回的是第一個元素地址,所以必須提早一個位置停止(區間的結尾不包括在區間內)。
除了以上已用叠代器,還有以下三種插入叠代器:
back_insert_iterator:將元素插入容器尾部中
front_insert_iterator:將元素插入容器前端
insert_iterator:將元素插入指定的位置前面
以上三種叠代器可以提高STL算法通用性,可以將容器類型作為模版參數。例如:
back_insert_iterator<vector<int> > back_iter(dice)
insert_iterator<vector<int> > insert_iter(dice,dice.begin() );
#include <iostream> #include <vector> #include <iterator> #include <algorithm> #include <string> void output(const std::string &s) { std::cout << s << " "; } using namespace std; int main() { string s1[4] = { "fine" , "fish","fashion","fate" }; string s2[3] = { "I" , "am" , "Zhang" }; string s3[2] = { "Zeze" , "good" }; vector<string> words(4); copy(s1,s1 + 4,words.begin()); for_each(words.begin(),words.end(),output); cout << endl; copy(s2,s2 + 2,front_insert_iterator<vector<string> >(words)); for_each(words.begin(),words.end(),output); cout << endl; copy(s3,s3 + 2,insert_iterator<vector<string> >(words,words.begin())); for_each(words.begin(),words.end(),output); cout << endl; return 0; }
C++筆記------叠代器