迭代器

咱們知道可使用下標運算符來訪問,string對象的字符或者vector對象的元素。還有另一種機制能夠實現一樣的目的。這就是迭代器。除了vector以外,標準庫還定義了其餘幾種容器。全部標準庫容器均可以使用迭代器,可是其中只有少數幾種才同時支持下標運算符,相似指針類型,迭代器也提供了對對象的間接訪問。就是迭代器而言,其對象是容器中的元素或者string對象中的字符。使用迭代器能夠訪問某個元素,迭代器也能從一個元素移動到另一個元素。迭代器有有效和無效之分,這一點和指針相似。ios

一、使用迭代器:算法

和指針不同的是,獲取迭代器不是使用取地址符,有迭代器的類型同時擁有返回迭代器的成員。好比這些類型都擁有begin和end的成員,其中begin成員負責返回指向第一個元素(或第一個字符)的迭代器。函數

1
auto b=v.begin(),e=v.end(); //b和e的類型相同

end成員則負責返回指向容器(或string對象),「爲元素的下一位置」的迭代器。也就是該迭代器知識的是容器一個根本不存在的」尾後「元素。這樣迭代器沒有什麼含義,只是一個標記而已,代表咱們已經處理完了容器中的全部元素。end成員返回的迭代器常被稱做尾後迭代器或者簡稱爲尾迭代器。特殊狀況下若是容器爲空,則begin和end返回的是同一個迭代器。spa

若是容器爲空,則begin和end返回的是同一個迭代器,都是尾後迭代器。指針

二、迭代器運算符:code

 

* iter 返回迭代器iter所指元素的引用
iter->mem 解引用iter並獲取該元素的名爲mem的成員,等價於(*iter).mem
++iter 令iter指示容器中的下一個元素
--iter 令iter指示容器中的上一個元素
iter1==iter2 判斷兩個迭代器是否相等(不相等)。
iter1!=iter2 若是兩個迭代器指示1的是同一個元素或者他們是同一個容器的尾後迭代器,則相等,反之則不等。

和指針相似,也能經過解引用迭代器來獲取他所指示的元素,執行解引用的迭代器必須合法並確實指示着某個元素。試圖解引用一個非法迭代器或尾後迭代器都是爲被定義的行爲。對象

三、將迭代器從一個元素地用到另一個源素:ci

迭代器使用++運算符。來從一個元素移動到下一個元素。從邏輯上來講,迭代器的遞增和整數的遞增相似。整數的遞增是在整數值上加一,迭代器的遞增是將迭代器向前移動一個位置。get

由於end返回的迭代器並不實際指示某個元素,因此不能對其進行遞增或解引用的操做。string

1
2
3
4
5
6
7
string s( "wangs huai" );
     for  (auto t = s.begin(); t != s.end() && !isspace(*t); t +=  1 )
     {
         *t = toupper(*t);
     }
     cout << s << endl;
     getchar();

循環首先用s.begin的返回值來初始化t,意味着t指示的是s中的第一個字符。條件部分檢查是否已到達的、s的尾部。若是沒有到達,則將t解引用的結果傳入isspace函數檢查是否遇到了空白。每次迭代的最後,執行++t令迭代器向前移一個位置訪問s的下一個字符。

循環內部和上一個程序if語句的最後一句話同樣,先解引用t,而後將結果傳入toupper函數獲得該字母對應的大寫形式,再把這個大寫字母從新賦值給t所指示的字符。

注意:解引用和成員訪問操做:(*t).empty。爲了簡化這個操做,可使用->(箭頭運算符),將解引用和成員訪問兩個操做結合起來,也就是說t->mem和(*t).mem(),表達的意思是相同的。

四、迭代器類型。

就像不知道string和vector獨享的類型同樣,咱們一樣不知道(不用知道)迭代器的精確類型。而實際上,那些擁有迭代器類型的標準庫庫類型使用iterator和const_iterator來表示迭代器的類型。

注意:迭代器類型和迭代器:

迭代器有3種不一樣的概念:(1)迭代器(2)指容器定義的迭代器類型(3)某個迭代器對象

五、begin和end運算符:
他們的返回具體類型由對象是不是常量決定,若是是常量,begin和end返回的是const_iterator,若是對象不是常量,返回iterator;

六、某些對vector對象的操做會對迭代器失效:

vector對象能夠動態的延長,可是也會有一些反作用,已知一個限制是不能在範圍for循環中向vector對象添加源素。另一個限制是任何一種可能改變vector對象容量的操做,好比:push_back,都會使該vector對象的迭代器失效。

凡是咱們使用了迭代器的循環體,都不要向迭代器所屬的容器中添加源素。

七、迭代器運算:

迭代器遞增運算每次移動一個元素,全部標註庫容器都有支持遞增運算的迭代器。相似的,也能用==和!=對任意標準庫類型的兩個有效迭代器進行比較。

string和vector的迭代器提供了更多的運算符。一方面能夠迭代器每次移動跨過多個元素,另外也支持迭代器進行關係運算。全部這些運算被稱爲迭代器運算。

vector和string迭代器支持的運算:

iter+n 迭代器加上一個整數值任得一個迭代其,迭代器指示的新位置與原來相比向前移動了n個位置。
iter-n 迭代器減去一個整數值任得一個迭代其,迭代器指示的新位置與原來相比向後移動了n個位置。
iter1+=n 迭代器加法的複合賦值語句,將iter加n的結果賦給iter1
iter-=n 迭代器減法的複合賦值語句,將iter1-n的結果賦值給iter1
iter1-iter2 獲得他們之間的距離

八、迭代器的算術運算:

能夠令迭代器和一個整數值相加(或相減),其返回值是向前或者向後移動了若干個位置的迭代器。執行這樣的操做時,結果迭代器或者指示原vector對象(或string對象)內的一個元素,或者指示原vector對象(string對象)尾元素的下一個位置。

例如:計算最接近中間元素的算法:mid=begin+(size)/2;

對於sring和vector對象的迭代器來講,除了判斷是否相等,還能使用關係運算符對其進行比較。

if(t<mid)//處理前半部分的元素。

九、使用迭代器運算:

使用迭代器運算的一個經典算法就是二分查找。用二分查找實現迭代器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# include <iostream>
# include <string>
# include <vector>
using std::vector;
using  namespace  std;
int  main()
{
     int  sought =  0 ;
     vector< int >myvector{ 1 , 3 , 2 , 4 , 5 , 0 , 9 , 6 , 8 , 7 };
     auto beg = myvector.begin(), end = myvector.end();
     auto mid = beg + (end - beg) /  2 ;
     while  (mid != end&&*mid != sought)
     {
         if  (sought < *mid)
         {
             end=mid;
         }
         else
         {
             beg = mid +  1 ;
         }
         mid = beg + (end - beg) /  2 ;
     }
     cout << sought <<  ":"  << endl;
     getchar();
     return  0 ;
}

程序剛開始就定義了三個迭代器:被惡搞指向搜索範圍內的第一個元素,end指向尾元素的下一位置,mid指向中間那個元素。初始狀態下,搜索範圍是名爲myvector的vector《string》的所有範圍。

循環部分先判斷所搜範圍是否爲空,若是mid和end當前值相等,說明已經找遍了全部元素。此時條件不知足,循環終止。當搜索範圍不爲空是,可知密度指向了某個元素,檢查該元素是否就是咱們所要搜索的,若是是就終止循環。

當進入循環內部以後,程序經過某種規則移動beg或者end來縮小範圍。

注意:就像不知道string和vector的size_type成員究竟是什麼類型同樣,通常說來,咱們也不知道(不用知道)迭代器的精確類型。而實際上,那些擁有迭代器的標準庫類型使用iterator和const_iterator來表示迭代器的類型。

注意:iterator是迭代器的意思,const_iterator是常迭代器,是用來讀取數據的。

相關文章
相關標籤/搜索