1. 程式人生 > >c++迭代器(iterator)詳解【轉】

c++迭代器(iterator)詳解【轉】

(轉自:https://www.cnblogs.com/hdk1993/p/4419779.html

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_iterator citer=ivec.begin();citer!=ivec.end();citer++)
{
cout<<*citer;
//*citer=3; error
}


vector<int>::const_iterator 和 const vector<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; 

 

 

2. Iterator(迭代器)模式
一、概述
    Iterator(迭代器)模式又稱Cursor(遊標)模式,用於提供一種方法順序訪問一個聚合物件中各個元素, 而又不需暴露該物件的內部表示。或者這樣說可能更容易理解:Iterator模式是運用於聚合物件的一種模式,通過運用該模式,使得我們可以在不知道物件內部表示的情況下,按照一定順序(由iterator提供的方法)訪問聚合物件中的各個元素。
    由於Iterator模式的以上特性:與聚合物件耦合,在一定程度上限制了它的廣泛運用,一般僅用於底層聚合支援類,如STL的list、vector、stack等容器類及ostream_iterator等擴充套件iterator。


    根據STL中的分類,iterator包括:
Input Iterator:只能單步向前迭代元素,不允許修改由該類迭代器引用的元素。
Output Iterator:該類迭代器和Input Iterator極其相似,也只能單步向前迭代元素,不同的是該類迭代器對元素只有寫的權力。
Forward Iterator:該類迭代器可以在一個正確的區間中進行讀寫操作,它擁有Input Iterator的所有特性,和Output Iterator的部分特性,以及單步向前迭代元素的能力。
Bidirectional Iterator:該類迭代器是在Forward Iterator的基礎上提供了單步向後迭代元素的能力。
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模式有三個重要的作用:
1)它支援以不同的方式遍歷一個聚合.複雜的聚合可用多種方式進行遍歷,如二叉樹的遍歷,可以採用前序、中序或後序遍歷。迭代器模式使得改變遍歷演算法變得很容易: 僅需用一個不同的迭代器的例項代替原先的例項即可,你也可以自己定義迭代器的子類以支援新的遍歷,或者可以在遍歷中增加一些邏輯,如有條件的遍歷等。
2)迭代器簡化了聚合的介面. 有了迭代器的遍歷介面,聚合本身就不再需要類似的遍歷介面了,這樣就簡化了聚合的介面。
3)在同一個聚合上可以有多個遍歷 每個迭代器保持它自己的遍歷狀態,因此你可以同時進行多個遍歷。
4)此外,Iterator模式可以為遍歷不同的聚合結構(需擁有相同的基類)提供一個統一的介面,即支援多型迭代。
    簡單說來,迭代器模式也是Delegate原則的一個應用,它將對集合進行遍歷的功能封裝成獨立的Iterator,不但簡化了集合的介面,也使得修改、增 加遍歷方式變得簡單。從這一點講,該模式與Bridge模式、Strategy模式有一定的相似性,但Iterator模式所討論的問題與集合密切相關, 造成在Iterator在實現上具有一定的特殊性,具體將在示例部分進行討論。


四、優缺點
     正如前面所說,與集合密切相關,限制了 Iterator模式的廣泛使用,就個人而言,我不大認同將Iterator作為模式提出的觀點,但它又確實符合模式“經常出現的特定問題的解決方案”的 特質,以至於我又不得不承認它是個模式。在一般的底層集合支援類中,我們往往不願“避輕就重”將集合設計成集合 + Iterator 的形式,而是將遍歷的功能直接交由集合完成,以免犯了“過度設計”的詬病,但是,如果我們的集合類確實需要支援多種遍歷方式(僅此一點仍不一定需要考慮 Iterator模式,直接交由集合完成往往更方便),或者,為了與系統提供或使用的其它機制,如STL演算法,保持一致時,Iterator模式才值得考 慮。


五、舉例
    可以考慮使用兩種方式來實現Iterator模式:內嵌類或者友元類。通常迭代類需訪問集合類中的內部資料結構,為此,可在集合類中設定迭代類為friend class,但這不利於新增新的迭代類,因為需要修改集合類,新增friend class語句。也可以在抽象迭代類中定義protected型的存取集合類內部資料的函式,這樣迭代子類就可以訪問集合類資料了,這種方式比較容易新增新的迭代方式,但這種方式也存在明顯的缺點:這些函式只能用於特定聚合類,並且,不可避免造成程式碼更加複雜。
    STL的list::iterator、deque::iterator、rbtree::iterator等採用的都是外部Iterator類的形式,雖然STL的集合類的iterator分散在各個集合類中,但由於各Iterator類具有相同的基類,保持了相同的對外的介面(包括一些traits及tags等,感興趣者請認真閱讀參考1、2),從而使得它們看起來仍然像一個整體,同時也使得應用algorithm成為可能。我們如果要擴充套件STL的iterator,也需要注意這一點,否則,我們擴充套件的iterator將可能無法應用於各algorithm。