詳解C++中的vector容器及用迭代器訪問vector的方法
vector
vector是相同類型對象的集合。集合中的每個(gè)對象有個(gè)對應(yīng)的索引。vector常被稱為容器(container)。
為了使用vector,需要:
#include <vector> using std::vector;
vector是一個(gè)類模版(class template)。C++有函數(shù)模版和類模版。模版本身不是函數(shù)或類,必須通過指定 類型讓編譯器去實(shí)例化(instantiation)它。比如vector<int> ivec。
vector是模版,不是類型。從vector得到的類型要包含元素的類型。
早期C++定義vector的元素是vector是,最后一個(gè)閉括號前必須有一個(gè)空格,如vector<vector<int> >。但是C++ 11不要求這樣。
定義和初始化vectors
最常有的定義vectors的方法如下:
方法 | 解釋 |
---|---|
vector |
默認(rèn)初始化,v1是空的 |
vector |
v2有v1每個(gè)元素的拷貝 |
vector |
等價(jià)于v2(v1)| |
vector |
v3有n個(gè)val |
vector |
v3有n個(gè)元素,每個(gè)元素是value-initialized |
vector |
v5的元素即a, b, c, ... |
vector |
等價(jià)于v5{a, b, c, ...} |
需要注意的是,最常用使用vector的方法就是定義一個(gè)起初為空的vector,即vector<T> v,在運(yùn)行時(shí)指定元素。
vector的列表初始化(list initializing)
上面使用花括號(curly brace)的方法是列表初始化,是C++ 11引入的。
比如,
vector<string> articles = {"an", "a", "the"};
我們看到C++有很多初始化的方式,很多情況下它們是可以互換的,但有些時(shí)候初始化的形式是不能換的:
當(dāng)使用拷貝初始化形式(即使用=),只能提供單個(gè)初始化器
當(dāng)提供in-class初始化,只能是拷貝初始化或者花括號
列表初始化只能使用花括號,不能是圓括號
有關(guān)value-initialized
前面提到vector<int> ivec(10)這種只指定元素個(gè)數(shù)的初始化方法,每個(gè)元素是value-initialized。即:
對內(nèi)置類型,值為0
對類類型,使用默認(rèn)初始化
花括號,圓括號
vector<int> v1(10); // 10個(gè)元素,都是0 vector<int> v1{10}; // 1個(gè)元素,是10 vector<int> v1{10, 1}; // 2個(gè)元素,分別是10, 1 vector<int> v1(10, 1); // 10個(gè)元素,都是1
需要注意的是,使用{}并不一定就是列表初始化;它表示: 如果可能的話,使用列表初始化。
vector<string> v5{"hi"}; // ok, list initialization vector<string> v6("hi"); // error: cann't construct vector from string lieral vector<string> v7{10}; // has ten default-initialized value.
上面的v7就使用花括號指定個(gè)數(shù),而不是列表初始化。
向vector添加元素
使用push_back方法。
重要概念:vector高效增長:
標(biāo)準(zhǔn)要求vector的實(shí)現(xiàn)能夠在運(yùn)行時(shí)高效添加。如果在定義vector時(shí)指定了大小,就顯得沒必要,甚至導(dǎo)致 差的性能。總之,一般直接開始定義一個(gè)空的vector。
另外,我們要確保即使循環(huán)改變了vector的大小,循環(huán)也是正確的。因此,不能在range for里面向vector添加元素。
其它的vector操作
最常用的操作有:
方法 |
---|
v.empty() |
v.size() |
v.push_back(t) |
v[n] |
==, !=, <, <=, >, >= |
類似的,v.size()返回的類型也是size_type的。需要注意的是,模版類的類型始終是包括元素類型的,
vector<int>::size_type // ok vector::size_type // error
關(guān)于下標(biāo)訪問,它只能訪問已經(jīng)存在的元素,不會添加。
vector<int> ivec; cout << ivec[0]; // error for (decltype(ivev.size()) ix = 0; ix != 10; ix++) ivec[ix] = ix; // disaster: has no element
迭代器
盡管我們可以使用下標(biāo)來訪問字符串中的字符或vector的元素,但更一般的機(jī)制是使用迭代器(iterator)。
所有的容器都支持迭代器,但僅少數(shù)幾個(gè)支持下標(biāo)操作。
合法的迭代器:
- 指示某個(gè)元素
- 指示最后一個(gè)元素的下一個(gè)位置
- 其它的迭代器都是不合法的。
- 使用迭代器
使用begin和end成員函數(shù)。
// b 指示第一個(gè)元素;e 指示最后一個(gè)元素的下一個(gè)位置 auto b = v.begin(), e = v.end();
一般我們不必關(guān)心迭代器的準(zhǔn)確類型,所以直接使用auto。
end返回的迭代器一般被稱為off-the-end迭代器,或者縮寫為end迭代器。
顯然,如果一個(gè)容器為空,begin返回的和end返回的相同。
迭代器的操作
| 方法 | 解釋 | | iter | 返回指示元素的引用 | | iter->mem | 解引用iter,并獲取名字為mem的成員,等價(jià)于 (iter).mem | | ++iter | 增加iter,指示下一個(gè) | | --iter | 減小iter,指示前一個(gè) | | == , != | 比較 |
下面是把遇到空白字符前的字符轉(zhuǎn)成大寫。
for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it) *it = toupper(*it);
熟悉C或者Java語言的人可能需要習(xí)慣C++里面for循環(huán)一般都是使用!=結(jié)束,而不是使用<。 這是因?yàn)椋械娜萜鞯牡鞫级x了!=和==方法;而絕大部份迭代器沒有<方法。通過使用!=,我們可以不必 關(guān)心處理容器的準(zhǔn)確類型。
迭代器的類型
就像我們不知道vector或string的size_type的準(zhǔn)確類型,我們一般也不知道迭代器的準(zhǔn)確類型。
庫類型的迭代器定義了iterator和const_iterator兩種類型。
vector<int>::iterator it; // 可讀,可寫 vector<int>::iterator it2; // 可讀,可寫 vector<int>::const_iterator it3; // 可讀,不能寫
const_iterator的行為類似一個(gè)const指針。就像const指針,const_iterator不能修改所指示的元素。如果 一個(gè)vector或者字符串是const的,那么只能使用const_iterator。
如果對象是const的,那么begin和end返回的就是const_iterator;如果對象不是const的,返回的就是iterator。 但這種行為有時(shí)不是我們想要的,即針對非const對象,我們也希望得到const_iterator。C++ 11引入了兩個(gè)新的函數(shù), cbegin和cend解決了這一問題。
auto it3 = v.cbegin();
解引用和訪問成員
當(dāng)對迭代器解引用時(shí),得到的是其指示的對象。如果該對象是個(gè)類類型的,我們可能要訪問其的成員。舉個(gè)例子,一個(gè)字符串的vector可能想知道 給定元素是否為空,可以使用(*it).empty()。
需要注意的是,(*it).empty()這個(gè)括號是必須的。否則,點(diǎn)操作符直接作用于it。因此,*it.empty()是錯(cuò)誤的。
為了簡化這種表示,語言定義了箭頭操作符(->),它把解引用和成員訪問組合為一個(gè)符號,即it->empty()。
迭代器的算術(shù)
自增與自減是所有迭代器都支持的操作。
而對于string和vector的迭代器,還支持額外的算術(shù)操作。
| 方法 | | iter + n | | iter - n | | iter1 += n | | iter2 -= n | | iter1 - iter2 | | >, >=, <, <= |
比如,計(jì)算vector中間位置,
auto mid = vi.begin() + vi.size() / 2;
需要注意的是,迭代器的相加是不合法的。
您可能感興趣的文章
- 04-02c語言沒有round函數(shù) round c語言
- 01-10求子數(shù)組最大和的解決方法詳解
- 01-10深入二叉樹兩個(gè)結(jié)點(diǎn)的最低共同父結(jié)點(diǎn)的詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車次數(shù)的問題詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)-用棧實(shí)現(xiàn)表達(dá)式求值的方法詳解
- 01-10HDOJ 1443 約瑟夫環(huán)的最新應(yīng)用分析詳解
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10如何查看進(jìn)程實(shí)際的內(nèi)存占用情況詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法