C++ 學(xué)習(xí)筆記之——STL 庫(kù) vector

vector 是一種順序容器,可以看作是可以改變大小的數(shù)組。

就像數(shù)組一樣届榄,vector 占用連續(xù)的內(nèi)存地址來(lái)存儲(chǔ)元素,因此可以像數(shù)組一樣用偏移量來(lái)隨機(jī)訪問(wèn)倔喂,但是它的大小可以動(dòng)態(tài)改變铝条,容器會(huì)自動(dòng)處理內(nèi)存分配問(wèn)題。

在內(nèi)部席噩,vector 使用動(dòng)態(tài)分配的數(shù)組來(lái)存儲(chǔ)元素班缰,當(dāng)新元素插入時(shí),如果現(xiàn)有的存儲(chǔ)空間已經(jīng)占滿悼枢,則需要重新再分配一個(gè)新的數(shù)組埠忘,并且將之前的元素都移動(dòng)到新的內(nèi)存上。這個(gè)過(guò)程是非常耗時(shí)的,因此莹妒,vector 并不會(huì)在每次插入新元素時(shí)都重新分配內(nèi)存名船。

相反,vector 容器可能會(huì)分配一些額外的內(nèi)存來(lái)適應(yīng)其大小的增長(zhǎng)动羽,因此包帚,其真實(shí)容量可能比存儲(chǔ)這些元素實(shí)際需要的內(nèi)存要大。庫(kù)通過(guò)不同的策略來(lái)平衡內(nèi)存占用和空間再分配运吓,但無(wú)論如何渴邦,空間分配只應(yīng)在 vector 大小以對(duì)數(shù)增長(zhǎng)的時(shí)候發(fā)生,以便在向量末尾插入單個(gè)元素可以做到均攤情況下是常數(shù)級(jí)的時(shí)間復(fù)雜度拘哨。

因此谋梭,相對(duì)于數(shù)組,vector 會(huì)消耗更多的內(nèi)存來(lái)?yè)Q取更有效地對(duì)內(nèi)存進(jìn)行管理并且動(dòng)態(tài)增長(zhǎng)倦青。

相對(duì)于其他動(dòng)態(tài)容器瓮床,vector 支持隨機(jī)訪問(wèn),并且能相對(duì)高效地在末尾插入或者刪除元素产镐,但如果要在其他位置插入或者刪除元素隘庄,vector 就會(huì)表現(xiàn)得很差,而且迭代器和引用也不是那么方便癣亚。

構(gòu)造函數(shù)

  • explicit vector (const allocator_type& alloc = allocator_type()); 默認(rèn)構(gòu)造函數(shù)丑掺,構(gòu)造出一個(gè)不包含任何元素的空的 vector;

  • explicit vector (size_type n); 構(gòu)造出一個(gè)包含 n 個(gè)元素的 vector述雾,默認(rèn)會(huì)初始化為 0街州;

  • explicit vector (size_type n, const value_type& val, const allocator_type& alloc = allocator_type()); 構(gòu)造出一個(gè)包含 n 個(gè)值為 val 的 vector;

  • vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()); 構(gòu)造出一個(gè)包含迭代器 [first, end) 范圍內(nèi)元素的 vector玻孟,注意左閉右開(kāi)唆缴;

  • vector (const vector& x); 復(fù)制構(gòu)造函數(shù),構(gòu)造出一個(gè)和 x 相同的 vector黍翎;

#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> first;                                 // 空的 vector
    vector<int> second (4, 100);                       // 包含 4 個(gè)值為 100 元素的 vector面徽,[100, 100, 100, 100]
    vector<int> third (second.begin(), second.end()); // 包含 second 起始迭代器到終止迭代器區(qū)間元素的 vector,[100, 100, 100, 100]
    vector<int> fourth (third);                       // 對(duì) third 的復(fù)制玩敏,[100, 100, 100, 100]

    // 數(shù)組也可以用來(lái)作為迭代器初始化 vector
    int myints[] = {16, 2, 77, 29};
    vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); //[16, 2, 77, 29]
    vector<int> sixth (4); // [0, 0, 0, 0]

    cout << "The contents of fifth are:";
    for (vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
        cout << ' ' << *it;
    cout << '\n';

    return 0;
}

賦值運(yùn)算

賦值運(yùn)算會(huì)給容器賦予新的內(nèi)容斗忌,替換掉舊的內(nèi)容,同時(shí)改變其大小旺聚。

#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> foo (3,0);
    vector<int> bar (5,0);

    bar = foo;
    foo = vector<int>();

    cout << "Size of foo: " << int(foo.size()) << '\n'; // 0
    cout << "Size of bar: " << int(bar.size()) << '\n'; // 3
    return 0;
}

迭代器

  • iterator begin(); 返回指向 vector 中第一個(gè)元素的迭代器织阳;
  • iterator end(); 返回一個(gè)迭代器,引用向量容器中的 past-the-end 元素砰粹,也即最后一個(gè)元素之后的理論元素唧躲;
  • reverse_iterator rbegin(); 返回指向 vector 中最后一個(gè)元素的反向迭代器造挽,增加反向迭代器會(huì)使它們向前移動(dòng);
  • reverse_iterator rend(); 返回一個(gè)反向迭代器弄痹,指向向量中第一個(gè)元素之前的理論元素饭入;
#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> myvector;
    for(int i = 0; i < 5; i++)
    {
      myvector.push_back(i);
    }

    vector<int>::iterator it = myvector.begin();

    for (; it != myvector.end(); it++)
    {
      cout << *it << '\t';
    }
    cout << endl;

    vector<int>::reverse_iterator rit = myvector.rbegin();

    for (; rit != myvector.rend(); rit++)
    {
      cout << *rit << '\t';
    }
    cout << endl;

    return 0;
}
// 0    1   2   3   4
// 4    3   2   1   0

也可以對(duì)向量建立指針,然后通過(guò)指針來(lái)訪問(wèn)成員函數(shù)肛真⌒扯或者建立引用。

#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> myvector;
    for(int i = 0; i < 5; i++)
    {
      myvector.push_back(i);
    }

    vector<int> *p = &myvector;
    p->push_back(5);

    vector<int>::reverse_iterator rit = p->rbegin();
    //   vector<int>::reverse_iterator rit = (*p).rbegin();


    for (; rit != p->rend(); rit++)
    {
      cout << *rit << '\t';
    }
    cout << endl;

    vector<int> &ref_myvector = myvector;
    ref_myvector.push_back(6);

    vector<int>::iterator it = ref_myvector.begin();

    for (; it != ref_myvector.end(); it++)
    {
      cout << *it << '\t';
    }
    cout << endl;

    return 0;
}
// 5    4    3   2   1   0
// 0    1   2   3   4   5   6

容量

  • size_type size() const; 返回向量中元素的個(gè)數(shù)蚓让;
  • size_type max_size() const; 返回向量中最大可能包含的元素個(gè)數(shù)乾忱,但這只是理論上的;
  • void resize (size_type n, value_type val = value_type()); 重新設(shè)置向量的大小使之包含 n 個(gè)元素历极;如果 n 小于現(xiàn)有向量大小窄瘟,則只保留前 n 個(gè)元素;如果 n 大于現(xiàn)有向量大小趟卸,那么在末尾插入元素來(lái)使向量大小達(dá)到 n 蹄葱;如果 n 大于現(xiàn)有向量容量,那么會(huì)自動(dòng)重新分配內(nèi)存锄列;
  • size_type capacity() const; 返回向量當(dāng)前分配的內(nèi)存可以包含多少個(gè)元素图云;
  • bool empty() const; 返回當(dāng)前向量是否為空,也就是大小是否為零邻邮;
  • void reserve (size_type n); 讓向量當(dāng)前分配的內(nèi)存至少可以包含 n 個(gè)元素琼稻;
#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> myvector;
    cout << "max_size: " << myvector.max_size() << endl;

    // 添加元素的過(guò)程中容量會(huì)不斷增大
    for(int i = 0; i < 10; i++)
    {
        myvector.push_back(i);
        cout << "size: " << myvector.size() << '\t';
        cout << "capacity: " << myvector.capacity() << endl;
    }

    vector<int> othervector;
    othervector.reserve(100);
    // 添加元素的過(guò)程中大小不超過(guò) 100 就不會(huì)增大
    for(int i = 0; i < 10; i++)
    {
        othervector.push_back(i);
        cout << "size: " << othervector.size() << '\t';
        cout << "capacity: " << othervector.capacity() << endl;
    }

    return 0;
}

元素訪問(wèn)

  • reference operator[] (size_type n); 像數(shù)組一樣訪問(wèn)位置 n 處的元素,但不會(huì)進(jìn)行邊界檢測(cè)饶囚;
  • reference at (size_type n); 訪問(wèn)位置 n 處的元素,但會(huì)進(jìn)行邊界檢測(cè)鸠补;
  • reference front(); 返回向量中第一個(gè)元素的引用萝风;
  • reference back(); 返回向量中最后一個(gè)元素的引用;
#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> myvector;

    for(int i = 0; i < 10; i++)
    {
        myvector.push_back(i);

    }

    cout << myvector.front() << endl;
    cout << myvector.back() << endl;

    // 此處越界訪問(wèn)向量紫岩,不會(huì)提示
    for(int i = 0; i <= myvector.size(); i++)
    {
        cout << myvector[i] << '\t';
    }
    cout << endl;

    // 此處越界訪問(wèn)向量规惰,會(huì)拋出一個(gè) out_of_range 異常
    for(int i = 0; i <= myvector.size(); i++)
    {
        cout << myvector.at(i) << '\t';
    }
    cout << endl;

    return 0;
}

向量修改

  • void assign (InputIterator first, InputIterator last); 給向量重新分配迭代器 [first, end) 范圍內(nèi)的元素,注意左閉右開(kāi)泉蝌;
  • void assign (size_type n, const value_type& val); 給向量重新分配 n 個(gè)值 val 的元素歇万;
  • void push_back (const value_type& val); 在向量末尾添加一個(gè)元素;
  • void pop_back(); 從向量末尾刪除一個(gè)元素勋陪;
  • iterator insert (iterator position, const value_type& val); 在迭代器位置前面插入一個(gè)元素贪磺,返回指向第一個(gè)新插入元素的迭代器
  • void insert (iterator position, size_type n, const value_type& val); 在迭代器位置前面插入 n 個(gè)值 val 的元素诅愚;
  • void insert (iterator position, InputIterator first, InputIterator last); 在迭代器位置前面插入迭代器 [first, end) 范圍內(nèi)的元素寒锚;
  • iterator erase (iterator position); 刪除迭代器位置的元素,返回最后一個(gè)被刪除元素的后面一個(gè)元素的迭代器
  • iterator erase (iterator first, iterator last); 刪除迭代器 [first, end) 范圍內(nèi)的元素刹前,返回最后一個(gè)被刪除元素的后面一個(gè)元素的迭代器泳赋;
  • void swap (vector& x); 和向量 x 進(jìn)行交換,兩個(gè)向量元素類型相同喇喉,但大小可能不同祖今;
  • void clear(); 清空向量;
#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> first;
    vector<int> second;
    vector<int> third;

    first.assign(7, 100);             // [100, 100, 100, 100, 100, 100, 100]

    vector<int>::iterator it;
    it = first.begin() + 1;

    second.assign(it, first.end() - 1); // [100, 100, 100, 100, 100]

    int myints[] = {1776, 7, 4};
    third.assign(myints, myints + 3);   // [1776, 7, 4]

    cout << "Size of first: " << int (first.size()) << '\n';
    cout << "Size of second: " << int (second.size()) << '\n';
    cout << "Size of third: " << int (third.size()) << '\n';

    vector<int> myvector (3, 100); // [100, 100, 100]

    it = myvector.begin() + 1;
    it = myvector.insert(it, 200); // [100, 200, 100, 100]拣技,此時(shí) it 指向新插入的元素 200

    myvector.insert(it, 2, 300); // [100, 300, 300, 200, 100, 100]千诬,此時(shí) it 無(wú)效了

    it = myvector.begin();

    vector<int> anothervector (2, 400);  // [400, 400]

    myvector.insert(it + 2, anothervector.begin(), anothervector.end());
    // [100, 300, 400, 400, 300, 200, 100, 100]

    int myarray [] = {501, 502, 503};
    myvector.insert (myvector.begin(), myarray, myarray + 3);
    // [501, 502, 503, 100, 300, 400, 400, 300, 200, 100, 100]

    cout << "myvector contains:";
    for (it = myvector.begin(); it < myvector.end(); it++)
        cout << ' ' << *it;
    cout << '\n';

    myvector.clear();
    for (int i = 1; i <= 10; i++) myvector.push_back(i);
    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    it = myvector.erase(myvector.begin() + 5);
    // [1, 2, 3, 4, 5, 7, 8, 9, 10],此時(shí) it 指向 6 后面的元素 7

    it = myvector.erase(myvector.begin(), myvector.begin() + 3);
    // [4, 5, 7, 8, 9, 10]过咬,此時(shí) it 指向 3 后面的元素 4

    cout << "myvector contains:";
    for (unsigned i = 0; i < myvector.size(); ++i)
        cout << ' ' << myvector[i];
    cout << '\n';

    return 0;
}

參考資料 [http://www.cplusplus.com]

獲取更多精彩大渤,請(qǐng)關(guān)注「seniusen」!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市掸绞,隨后出現(xiàn)的幾起案子泵三,更是在濱河造成了極大的恐慌,老刑警劉巖衔掸,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烫幕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡敞映,警方通過(guò)查閱死者的電腦和手機(jī)较曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)振愿,“玉大人捷犹,你說(shuō)我怎么就攤上這事∶崮” “怎么了萍歉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)档桃。 經(jīng)常有香客問(wèn)我枪孩,道長(zhǎng),這世上最難降的妖魔是什么藻肄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任蔑舞,我火速辦了婚禮,結(jié)果婚禮上嘹屯,老公的妹妹穿的比我還像新娘攻询。我一直安慰自己,他們只是感情好抚垄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蜕窿。 她就那樣靜靜地躺著谋逻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桐经。 梳的紋絲不亂的頭發(fā)上毁兆,一...
    開(kāi)封第一講書(shū)人閱讀 51,610評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音阴挣,去河邊找鬼气堕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛畔咧,可吹牛的內(nèi)容都是我干的茎芭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼誓沸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼梅桩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起拜隧,我...
    開(kāi)封第一講書(shū)人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宿百,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后洪添,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體垦页,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年干奢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痊焊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡忿峻,死狀恐怖薄啥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逛尚,我是刑警寧澤罪佳,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站黑低,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏酌毡。R本人自食惡果不足惜克握,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枷踏。 院中可真熱鬧菩暗,春花似錦、人聲如沸旭蠕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至佑稠,卻和暖如春秒梅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舌胶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工捆蜀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幔嫂。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓辆它,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親履恩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锰茉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355