C++迭代器(iterator)

1. 迭代器(iterator)是一中檢查容器內元素並遍歷元素的數據類型。
(1) 每種容器類型都定義了自己的迭代器類型,如vector:
vector<int>::iterator iter;這條語句定義了一個名爲iter的變量,它的數據類型是由vector<int>定義的iterator類型。

(2) 使用迭代器讀取vector中的每一個元素:
vector<int> ivec(10,1);
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)
{
*iter=2; //
使用 * 訪問迭代器所指向的元素
}
const_iterator:
只能讀取容器中的元素,而不能修改。
for(vector<int>::const_iteratorciter=ivec.begin();citer!=ivec.end();citer++)
{
cout<<*citer;
//*citer=3; error
}
vector<int>::const_iterator
和 constvector<int>::iterator的區別
const vector<int>::iterator newiter=ivec.begin();
*newiter=11; //
可以修改指向容器的元素
//newiter++; //迭代器本身不能被修改
(3) iterator的算術操作:

iterator除了進行++,--操作,可以將iter+n,iter-n賦給一個新的iteraor對象。還可以使用一個iterator減去另外一個iterator.
const vector<int>::iterator newiter=ivec.begin();
vector<int>::iterator newiter2=ivec.end();
cout<<"\n"<<newiter2-newiter;
一個很典型使用vector的STL程式
:
1 #include <vector>
2 #include <iostream>
3
4 using namespace std;
5
6 int main() {
7 vector<int> ivec;
8 ivec.push_back(1);
9 ivec.push_back(2);
10 ivec.push_back(3);
11 ivec.push_back(4);
12
13 for(vector<int>::iterator iter = ivec.begin();1. iter != ivec.end();++iter)
14 cout << *iter << endl;
15 }
2. Iterator(迭代器)模式

一、概述
Iterator(迭代器)模式又稱Cursor(遊標)模式,用於提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。或者這樣說可能更容易理解:Iterator模式是運用於聚合對象的一種模式,通過運用該模式,使得我們可以在不知道對象內部表示的情況下,按照一定順序(由iterator提供的方法)訪問聚合對象中的各個元素。
由於Iterator模式的以上特性:與聚合對象耦合,在一定程度上限制了它的廣泛運用,一般僅用於底層聚合支持類,如STL的list、vector、stack等容器類及ostream_iterator等擴展iterator。
根據STL中的分類,iterator包括:
Input Iterator:只能單步向前迭代元素,不允許修改由該類迭代器引用的元素。
Output Iterator:該類迭代器和InputIterator極其相似,也只能單步向前迭代元素,不同的是該類迭代器對元素只有寫的權力。
Forward Iterator:該類迭代器可以在一個正確的區間中進行讀寫操作,它擁有InputIterator的所有特性,和OutputIterator的部分特性,以及單步向前迭代元素的能力。
Bidirectional Iterator:該類迭代器是在ForwardIterator的基礎上提供了單步向後迭代元素的能力。
Random Access Iterator:該類迭代器能完成上面所有迭代器的工作,它自己獨有的特性就是可以像指針那樣進行算術計算,而不是僅僅只有單步向前或向後迭代。
這五類迭代器的從屬關係,如下圖所示,其中箭頭A→B表示,A是B的強化類型,這也說明了如果一個算法要求B,那麼A也可以應用於其中。

input output
\ /
forward
|
bidirectional
|
random access
圖1、五種迭代器之間的關係

vector 和deque提供的是RandomAccessIterator,list提供的是BidirectionalIterator,set和map提供的iterators是ForwardIterator,關於STL中iterator迭代器的操作如下:
說明:每種迭代器均可進行包括表中前一種迭代器可進行的操作。
迭代器操作 說明
(1)所有迭代器
p++ 後置自增迭代器
++p 前置自增迭代器
(2)輸入迭代器
*p 復引用迭代器,作爲右值
p=p1 將一個迭代器賦給另一個迭代器
p==p1 比較迭代器的相等性
p!=p1 比較迭代器的不等性
(3)輸出迭代器
*p 復引用迭代器,作爲左值
p=p1 將一個迭代器賦給另一個迭代器
(4)正向迭代器
提供輸入輸出迭代器的所有功能
(5)雙向迭代器
--p 前置自減迭代器
p-- 後置自減迭代器
(6)隨機迭代器
p+=i 將迭代器遞增i位
p-=i 將迭代器遞減i位
p+i 在p位加i位後的迭代器
p-i 在p位減i位後的迭代器
p[i] 返回p位元素偏離i位的元素引用
p<p1 如果迭代器p的位置在p1前,返回true,否則返回false
p<=p1 p的位置在p1的前面或同一位置時返回true,否則返回
false
p>p1 如果迭代器p的位置在p1後,返回true,否則返回
false
p>=p1 p的位置在p1的後面或同一位置時返回true,否則返回
false
只有順序容器和關聯容器支持迭代器遍歷,各容器支持的迭代器的類別如下:

容器 支持的迭代器類別 容器 支持的迭代器類別 容器 支持的迭代器類別
vector 隨機訪問 deque隨機訪問 list 雙向
set 雙向 multiset 雙向 map 雙向
multimap 雙向 stack不支持 queue 不支持
priority_queue 不支持
二、結構
Iterator模式的結構如下圖所示:


圖2、Iterator模式類圖示意
三、應用
Iterator模式有三個重要的作用:
1)它支持以不同的方式遍歷一個聚合.複雜的聚合可用多種方式進行遍歷,如二叉樹的遍歷,可以採用前序、中序或後序遍歷。迭代器模式使得改變遍歷算法變得很容易: 僅需用一個不同的迭代器的實例代替原先的實例即可,你也可以自己定義迭代器的子類以支持新的遍歷,或者可以在遍歷中增加一些邏輯,如有條件的遍歷等。
2)迭代器簡化了聚合的接口. 有了迭代器的遍歷接口,聚合本身就不再需要類似的遍歷接口了,這樣就簡化了聚合的接口。
3)在同一個聚合上可以有多個遍歷 每個迭代器保持它自己的遍歷狀態,因此你可以同時進行多個遍歷。
4)此外,Iterator模式可以爲遍歷不同的聚合結構(需擁有相同的基類)提供一個統一的接口,即支持多態迭代。
簡單說來,迭代器模式也是Delegate原則的一個應用,它將對集合進行遍歷的功能封裝成獨立的Iterator,不但簡化了集合的接口,也使得修改、增 加遍歷方式變得簡單。從這一點講,該模式與Bridge模式、Strategy模式有一定的相似性,但Iterator模式所討論的問題與集合密切相關, 造成在Iterator在實現上具有一定的特殊性,具體將在示例部分進行討論。
四、優缺點
正如前面所說,與集合密切相關,限制了Iterator模式的廣泛使用,就個人而言,我不大認同將Iterator作爲模式提出的觀點,但它又確實符合模式“經常出現的特定問題的解決方案”的 特質,以至於我又不得不承認它是個模式。在一般的底層集合支持類中,我們往往不願“避輕就重”將集合設計成集合 +Iterator 的形式,而是將遍歷的功能直接交由集合完成,以免犯了“過度設計”的詬病,但是,如果我們的集合類確實需要支持多種遍歷方式(僅此一點仍不一定需要考慮Iterator模式,直接交由集合完成往往更方便),或者,爲了與系統提供或使用的其它機制,如STL算法,保持一致時,Iterator模式才值得考 慮。
五、舉例
可以考慮使用兩種方式來實現Iterator模式:內嵌類或者友元類。通常迭代類需訪問集合類中的內部數據結構,爲此,可在集合類中設置迭代類爲friendclass,但這不利於添加新的迭代類,因爲需要修改集合類,添加friendclass語句。也可以在抽象迭代類中定義protected型的存取集合類內部數據的函數,這樣迭代子類就可以訪問集合類數據了,這種方式比較容易添加新的迭代方式,但這種方式也存在明顯的缺點:這些函數只能用於特定聚合類,並且,不可避免造成代碼更加複雜。
STL的list::iterator、deque::iterator、rbtree::iterator等採用的都是外部Iterator類的形式,雖然STL的集合類的iterator分散在各個集合類中,但由於各Iterator類具有相同的基類,保持了相同的對外的接口(包括一些traits及tags等,感興趣者請認真閱讀參考1、2),從而使得它們看起來仍然像一個整體,同時也使得應用algorithm成爲可能。我們如果要擴展STL的iterator,也需要注意這一點,否則,我們擴展的iterator將可能無法應用於各algorithm。
以下是一個遍歷二叉樹的Iterator的例子,爲了方便支持多種遍歷方式,並便於遍歷方式的擴展,其中還使用了Strategy模式(見筆記21):
(注:1、雖然下面這個示例是本系列所有示例中花費我時間最多的一個,但我不得不承認,它非常不完善,感興趣的朋友,可以考慮參考下面的參考材料將其補充完善,或提出寶貴改進意見。2、 我本想考慮將其封裝成與STL風格一致的形式,使得我們遍歷二叉樹必須通過Iterator來進行,但由於二叉樹在結構上較線性存儲結構複雜,使訪問必須 通過Iterator來進行,但這不可避免使得BinaryTree的訪問變得異常麻煩,在具體應用中還需要認真考慮。3、以下只提供了Inorder<中序>遍歷iterator的實現。)

 

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