STL之迭代器基本概念 [轉貼]

STL是C++中重要部分之一(面向對象、STL、模板等),其中三個基本的STL組件包括:
1. 迭代器。迭代器之於容器相當於指針之於數組,提供了訪問容器對象的方法,事實上C++中的指針也是一種迭代器,但是要注意迭代器不僅僅是指針,不一定具有地址值。
2. 容器。容器是一種模板類,例如list、vector、deques等,一般由迭代器訪問容器中的數據。
3. 算法。STL中數據結構和算法是分離的,各種函數在廣義容器中(包括鏈表、數組、string對象、容器)完全通用。

1.頭文件:
STL頭文件一般不使用.h擴展,其中主要使用的頭文件和對應容器類如下:
#include Container Class
<deque> deque
<list>  list
<map>  map, multimap
<queue> queue, priority_queue
<set>  set, multiset
<stack> stack
<vector> vector
<string>  string
<iterator> ***<***>::iterator
<algorithm> 各種算法函數
STL均使用標準命名空間using namespace std。

2.迭代器:
迭代器有五種類型,這五種類型是一種繼承關係,具體如下:
Input iterators:提供對數據的只讀訪問,前向推進。輸入迭代器可以使用==和!=來測試是否相等;使用*來訪問數據;使用++操作符前向推進。例如find函數需要保證輸入迭代器。
Output iterators:提供對數據的只寫訪問,前向推進。輸出迭代器缺省只寫,由於該迭代器無法讀取對象,因此不會在任何搜索和其他算法中使用它。
Forward iterators:提供讀寫訪問,前向推進。例如replace函數需要保證前向迭代器。
Bidirectional iterators:提供讀寫訪問,前向或後向推進。例如reverse函數需要保證雙向迭代器。
Random access iterators:提供讀寫訪問,隨機移動(非const的指針也是隨機迭代器)。STL中的排序和搜索函數使用隨機訪問迭代器,隨機訪問迭代器可以使用關係操作符做比較。
除此之外,還包括一些特殊的迭代器:
指針迭代器:一個指針也是一種迭代器。
常量迭代器:對於只讀變量,爲了防止錯誤賦值,可以使用常量迭代器const_iterator,該迭代器指向的對象不允許改變。注意:const ***<***>::iterator的含義是該迭代器成爲常量,不可指向其他數據,與常量迭代器的含義是不一樣的。

3.流迭代器
將輸入輸出(例如標準輸入輸出流cin/cout或者文件流等)作爲容器看待,因此接受迭代器參數的算法都可以和流一起工作。
STL定義模板類ostream_iterator作爲輸出流迭代器,其構造函數有兩個參數,包括一個ostream對象和一個string值(作爲間隔符),因此可以象下面一樣創建一個迭代器:
ostream_iterator<int>(cout, “/t”)             //定義cout迭代器
ofstream out(“text.txt”);
ostream_iterator<string> obegin(out, “/n”);       //定義文件流輸出迭代器
STL定義模板類istream_iterator作爲輸入流迭代器,可指定讀取的來源,並應該和結束迭代器比較。具體如下:
istream_iterator<int> intreader(cin);       //定義cin流迭代器
isteam_iterator<int> eof;
copy(istream_iterator<string>(cin), istream_iterator<string>(), 輸出迭代器);      //定義無變量名的cin流迭代器
ifstream in(“text.txt”);
istream_iterator<string> ibegin(in);
istream_iterator<string> iend;            //定義文件流輸入迭代器
還有一些具體應用如下:

//利用流迭代器填充vector
{
    ifstream 
in("test.txt");
    istream_iterator
<string> ibegin(in);
    istream_iterator
<string> iend;
    vector
<string> vec(ibegin, iend);
    copy(vec.begin(), vec.end(), ostream_iterator
<string>(cout, "/n"));
}

//利用輸入流填充vector
{
    vector
<string> vec;
    copy(istream_iterator
<string>(cin), istream_iterator<string>(), back_inserter(vec));
    sort(vec.begin(), vec.end());
    copy(vec.begin(), vec.end(), ostream_iterator
<string>(cout,"/n"));
}

//利用流迭代器保存vector內容到文件
{
    ifstream 
in("test.txt");
    istream_iterator
<string> ibegin(in);
    istream_iterator
<string> iend;
    vector
<string> vec(ibegin, iend);
    ofstream 
out("testcopy.txt");
    copy(vec.begin(), vec.end(), ostream_iterator
<string>(out"/n"));    
}

注意:上面用輸入流迭代器來初始化vector後,不可再用這個輸入流迭代器,因爲隨着數據的讀取,迭代器已經到達輸入流或者文件流的末尾了。

4.插入迭代器:
int arr[] = {1, 2, 3, 4, 5};
vector<int> vi;
copy(arr, arr + 5; vi.begin());
該語句不會執行,因爲沒有爲vi分配存儲空間。此時使用插入迭代器可以將值插入到容器中,自動爲vi擴展存儲空間,主要包括三種插入迭代器。
普通插入器:將對象插入到容器任何對象的前面。該迭代器使用容器的insert操作符替代賦值運算符,第一個參數是容器本身,第二個參數是容器迭代器指定插入位置。
Front inserters:將對象插入到數據集的前面,例如鏈表表頭。該迭代器使用push_front操作替代賦值運算符,參數是容器本身。
Back inserters:將對象插入到數據集的尾部,例如vector的尾部,導致vector容器擴展。該迭代器調用容器的push_back操作替代賦值運算符,參數是容器本身。
注意:使用插入迭代器可能導致容器中的其他對象移動位置,因此現有的迭代器變成非法,需要重新賦值(list除外,不受影響)。

int arr[] = {12345};
vector
<int> vi;
copy(arr, arr 
+ 5; front_iterator(vi));
//最終結果按序是5 4 3 2 1,因爲每次調用push_front將一個數據插入到vi的前面。
Vector<int>::iterator p = find(vi.begin(), vi.end(), 2);
copy(arr, arr 
+ 2, inserter(vi, p));
//最終結果是5 4 3 1 2 2 1,因爲調用insert一次性將所有數據插入到p前。


5.混合迭代器函數:
下面兩個迭代器函數非常有用:
advance(iterator, int):按照指定的數目增減迭代器。第一個參數是迭代器,第二個參數是增減的數目(前向迭代器該數必須爲正,雙向或者隨機迭代器該數可以爲負)。
distance(iterator, iterator, int&):返回到達一個迭代器所需遞增操作的數目。該函數是遞歸的,每次遞歸第三個參數,因此必須初始化該參數爲0然後使用該函數。

發佈了25 篇原創文章 · 獲贊 0 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章