咱們知道可使用下標運算符來訪問,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是常迭代器,是用來讀取數據的。