8. C++中各類容器的特點



1. vector的特點

內存特點: 內存空間連續(xù)爬橡,隨機訪問效率高莉擒。
插入刪除:插入或者刪除某個元素,需要將現有元素進行復制恋博,移動齐佳。

如果vector中存儲的對象很大,或者構造函數復雜交播,則在對現有元素進行拷貝時開銷較大重虑,因為拷貝對象要調用拷貝構造函數。對于簡單的小對象秦士,vector的效率優(yōu)于list缺厉。vector在每次擴張容量的時候,將容量擴展2倍隧土,這樣對于小對象來說提针,效率是很高的。
應用場景:vector適用于對象數量少曹傀,簡單對象辐脖,隨機訪問元素頻繁。支持高效的隨機訪問和尾端插入皆愉、刪除操作嗜价,其它位置的插入、刪除效率低下幕庐。

2. list

內存特點:內存空間不連續(xù)久锥,依靠指針來連接。具有雙鏈表結構异剥,每個元素維護一個前向和后向指針瑟由,因此支持前向、后向遍歷冤寿。
插入刪除:支持高效的隨機插入歹苦、刪除操作,但隨機訪問效率低下督怜,且需要額外維護指針殴瘦,開銷也較大。
應用場景: list適用于對象數量變化大亮蛔,對象復雜痴施,插入和刪除頻繁。

3. deque

內存特點:內存空間連續(xù),與vector類似辣吃,不同之處在于deque提供了兩級數據結構动遭,

  • 第一級完全類似于vector,代表實際容器
  • 另一級維護容器的首位地址神得。

插入刪除:支持高效的首端 尾端 插入/ 刪除操作厘惦。其它位置的插入、刪除效率低下哩簿。

4. vector宵蕉、list、deque比較

  • 隨機訪問操作节榜,選擇vector
  • 若已知存儲元素size羡玛,選擇vector
  • 需要隨機 插入 刪除,(不僅僅在兩端)宗苍,選擇list
  • 只有需要在首端進行插入稼稿、刪除操作的時候,才選擇deque讳窟,否則選擇vector
  • 若既需要隨機插入让歼、刪除,又需要隨機訪問丽啡,則需要在vector和list之間做折中谋右。
  • 當要存儲的是大型的數據類對象時,list要優(yōu)于vector补箍。
    (也可以使用vector來存儲指向對象的指針改执,同樣會取得較高的效率,但是指針的維護容易出錯坑雅,不推薦)

5. capacity vs size

  • capacity是容器需要增長之前天梧,能夠盛的元素總數;只有連續(xù)存儲的容器才有capacity的概念(例如vector霞丧,deque,string)冕香,list不需要capacity蛹尝。
  • size是容器當前存儲的元素的數目。
  • vector默認的容量初始值悉尾,以及增長規(guī)則是依賴于編譯器的突那。

6. 用vector存儲自定義類對象時,自定義類對象須滿足:

  • 有可供調用的無參構造函數
  • 有可用的拷貝賦值函數

7. 迭代器 iterator

  • vector與deque的迭代器支持算術運算
  • list的迭代器只能進行++/--操作构眯,不支持普通的算數運算愕难。

1. C++中vector 用法詳解


vector 詳細介紹

1. vector剖析:

vector 的數據安排以及操作方式,與 array 非常像似。兩者的唯一差別在于空間的運用彈性猫缭。

  • array是靜態(tài)空間
  • vector 是動態(tài)空間葱弟,隨著元素的加入,它的內部機制會自行擴充空間以容納新元素猜丹。
    因此芝加,vector 的運用對于內存的樽節(jié)與運用彈性有很大的幫助,我們再也不必因為害怕空間不足而一開始就要求一個大塊頭 array 了射窒,我們可以安心使用vector藏杖,吃多少用多少。

vector 的使用技術脉顿,關鍵在于其對大小的控制以及重新配置時的數據搬移效率蝌麸。
一旦 vector 舊有空間滿載,如果客端每新增一個元素艾疟,vector 內部只是擴充元素的空間来吩,實為不智,因為所謂擴充空間(不論多大)汉柒,在創(chuàng)建一個vector 后误褪,它會自動在內存中分配一塊連續(xù)的內存空間進行數據存儲,初始的空間大小可以預先指定也可以由vector 默認指定碾褂,這個大小即capacity ()函數的返回值兽间。當存儲的數據超過分配的空間時vector 會重新分配一塊內存塊,但這樣的分配是很耗時的正塌,在重新分配空間時它會做這樣的動作:

  • 首先嘀略,vector 會申請一塊更大的內存塊;(2的指數級增長)

  • 然后乓诽,將原來的數據拷貝到新的內存塊中帜羊;

  • 其次,銷毀掉原內存塊中的對象(調用對象的析構函數)鸠天;

  • 最后讼育,將原來的內存空間釋放掉。

2. vector 的特點:

  • 指定一塊如同數組一樣的連續(xù)存儲稠集,但空間可以動態(tài)擴展奶段。即它可以像數組一樣操作,并且可以進行動態(tài)操作剥纷。通常體現在push_back()pop_back() 痹籍。

  • 隨機訪問方便,它像數組一樣被訪問晦鞋,即支持[ ] 操作符和vector.at()

  • 節(jié)省空間蹲缠,因為它是連續(xù)存儲棺克,在存儲數據的區(qū)域都是沒有被浪費的,但是要明確一點vector 大多情況下并不是滿存的线定,在未存儲的區(qū)域實際是浪費的娜谊。

  • 在內部進行插入、刪除操作效率非常低渔肩,這樣的操作基本上是被禁止的因俐。Vector 被設計成只能在后端進行追加和刪除操作,其原因是vector 內部的實現是按照順序表的原理周偎。

  • 只能在vector 的最后進行push 和pop 抹剩,不能在vector 的頭進行push 和pop 。

  • 當動態(tài)添加的數據超過vector 默認分配的大小時要進行內存的重新分配蓉坎、拷貝與釋放澳眷,這個操作非常消耗性能。 所以要vector 達到最優(yōu)的性能蛉艾,最好在創(chuàng)建vector 時就指定其空間大小钳踊。

Vectors 包含著一系列連續(xù)存儲的元素,其行為和數組類似。訪問Vector中的任意元素或從末尾添加元素都可以在常量級時間復雜度內完成勿侯,而查找特定值的元素所處的位置或是在Vector中插入元素則是線性時間復雜度

3 vector的函數

  1. 1.Constructors 構造函數
vector<int> v1; //構造一個空的vector
vector<int> v1( 5, 42 ); //構造了一個包含5個值為42的元素的Vector

3.2.Operators 對vector進行賦值或比較

C++ Vectors能夠使用標準運算符: ==, !=, <=, >=,<, 和 >.
要訪問vector中的某特定位置的元素可以使用 [] 操作符.
兩個vectors被認為是相等的,如果:

  • 1.它們具有相同的容量
  • 2.所有相同位置的元素相等.

vectors之間大小的比較是按照詞典規(guī)則.

  1. 3.assign() 對Vector中的元素賦值
    語法:
void assign( input_iterator start, input_iterator end );
// 將區(qū)間[start, end)的元素賦到當前vector
void assign( size_type num, const TYPE &val );
// 賦num個值為val的元素到vector中,這個函數將會清除掉為vector賦值以前的內容.

4.at() 返回指定位置的元素

語法:

TYPE at( size_type loc );//差不多等同v[i];但比v[i]安全;,到后邊有例子說明

5.back() 返回最末一個元素
6.begin() 返回第一個元素的迭代器
7.capacity() 返回vector所能容納的元素數量(在不重新分配內存的情況下)
8.clear() 清空所有元素
9.empty() 判斷Vector是否為空(返回true時為空)
10.end() 返回最末元素的迭代器(譯注:實指向最末元素的下一個位置)
11.erase() 刪除指定元素
語法:

iterator erase( iterator loc );//刪除loc處的元素
iterator erase( iterator start, iterator end );//刪除start和end之間的元素

那好,既然刪除了元素,那我們來看看他的空間是不是也縮小了或者他的大小

void main( )
{
  vector<int> vec1;
  vec1.push_back(1);
  vec1.push_back(2);
  vec1.push_back(3);
  cout<<vec1.capacity()<<","<<vec1.size()<<endl;
  vec1.erase(vec1.begin());
  cout<<vec1.capacity()<<","<<vec1.size()<<endl;
  vec1.erase(vec1.begin());
  cout<<vec1.capacity()<<","<<vec1.size()<<endl;
  cout<<vec1[2];//在這里我們應該看到了拓瞪,如果用vec1.at(2)訪問肯定是非法的數據
}

從這個簡單的例子說明了一個問題,在erase刪除元素的時候助琐,并不會回收capacity容量的大小的祭埂,只是將元素向前移位,并且修改了size的大小兵钮,并不是真正意義上的刪除蛆橡,另外為了安全的訪問最好使用at()函數而不是下標訪問。

12.front() 返回第一個元素的引用
13.get_allocator() 返回vector的內存分配器
14.insert() 插入元素到Vector中

語法:

iterator insert( iterator loc, const TYPE &val );
//在指定位置loc前插入值為val的元素,返回指向這個元素的迭代器,
void insert( iterator loc, size_type num, const TYPE &val );
//在指定位置loc前插入num個值為val的元素
void insert( iterator loc, input_iterator start, input_iterator end );
//在指定位置loc前插入區(qū)間[start, end)的所有元素

15.max_size() 返回Vector所能容納元素的最大數量(上限)
16.pop_back() 移除最后一個元素
17.push_back() 在Vector最后添加一個元素
18.rbegin() 返回Vector尾部的逆迭代器
19.rend() 返回Vector起始的逆迭代器
20.reserve() 設置Vector最小的元素容納數量

補充說明

  • 1. 內存管理效率

四個內存相關函數

  • size():容器中實際容納了多少元素
    告訴你容器中有多少元素掘譬。它沒有告訴你容器為它容納的元素分配了多少內存泰演。

  • capacity():容器最大可容納的元素,如果超過此值葱轩,需要重新動態(tài)分配一塊1.5至2倍大小的內存睦焕,將現有元素賦值過去,然后銷毀之前的內存靴拱。
    告訴你容器在它已經分配的內存中可以容納多少元素复亏。那是容器在那塊內存中總共可以容納多少元素,而不是還可以容納多少元素缭嫡。如果你想知道一個vector或string中有多少沒有被占用的內存,你必須從capacity()中減去size()抬闷。如果size和capacity返回同樣的值妇蛀,容器中就沒有剩余空間了耕突,而下一次插入(通過insert或push_back等)會引發(fā)上面的重新分配步驟。

  • resize(): 強制容器容納N個元素
    強制把容器改為容納n個元素评架。調用resize之后眷茁,size將會返回n。如果n小于當前大小纵诞,容器尾部的元素會被銷毀上祈。如果n大于當前大小,新默認構造的元素會添加到容器尾部浙芙。如果n大于當前容量登刺,在元素加入之前會發(fā)生重新分配。

  • reserve(): 強制將容量改為N
    強制容器把它的容量改為至少n嗡呼,提供的n不小于當前大小纸俭。這一般強迫進行一次重新分配,因為容量需要增加南窗。(如果n小于當前容量揍很,vector忽略它,這個調用什么都不做万伤,string可能把它的容量減少為size()和n中大的數窒悔,但string的大小沒有改變。在我的經驗中敌买,使用reserve來從一個string中修整多余容量一般不如使用“交換技巧”简珠,那是條款17的主題。)

增加效率的方法

  1. 使用reserve()函數提前設定容量大小放妈,避免多次容量擴充操作導致效率低下北救。
    說明:在通過 reserve() 來申請?zhí)囟ù笮〉臅r候總是按指數邊界來增大其內部緩沖區(qū)。當進行insert或push_back等增加元素的操作時芜抒,如果此時動態(tài)數組的內存不夠用珍策,就要動態(tài)的重新分配當前大小的1.5~2倍的新內存區(qū),再把原數組的內容復制過去宅倒。所以攘宙,在一般情況下,其訪問速度同一般數組拐迁,只有在重新分配發(fā)生時蹭劈,其性能才會下降。
vector v;
v.reserve(1000);
for (int i = 1; i <= 1000; ++i) 
    v.push_back(i);
  1. 使用“交換技巧”來修整vector過氏哒伲空間/內存
vector(ivec).swap(ivec);

有一種方法來把它從曾經最大的容量減少到它現在需要的容量铺韧。

  1. 使用swap方法強行釋放STL vector 所占內存
template < class T> 
void ClearVector( vector& v )
{
  vector vtTemp;
  vtTemp.swap( v );
}

//如
vector v ;
nums.push_back(1);
nums.push_back(3);
nums.push_back(2);
nums.push_back(4);
vector().swap(v);
/* 或者v.swap(vector()); */
/*或者{ std::vector tmp = v;   v.swap(tmp);   }; //加大括號{ }是讓tmp退出{ }時自動析構*/


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缓淹,隨后出現的幾起案子哈打,更是在濱河造成了極大的恐慌塔逃,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件料仗,死亡現場離奇詭異湾盗,居然都是意外死亡,警方通過查閱死者的電腦和手機立轧,發(fā)現死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門格粪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人氛改,你說我怎么就攤上這事帐萎。” “怎么了平窘?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵吓肋,是天一觀的道長。 經常有香客問我瑰艘,道長是鬼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任紫新,我火速辦了婚禮均蜜,結果婚禮上,老公的妹妹穿的比我還像新娘芒率。我一直安慰自己囤耳,他們只是感情好发皿,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布亿蒸。 她就那樣靜靜地躺著,像睡著了一般展哭。 火紅的嫁衣襯著肌膚如雪匪蟀。 梳的紋絲不亂的頭發(fā)上椎麦,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音材彪,去河邊找鬼观挎。 笑死,一個胖子當著我的面吹牛段化,可吹牛的內容都是我干的嘁捷。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼显熏,長吁一口氣:“原來是場噩夢啊……” “哼雄嚣!你這毒婦竟也來了?” 一聲冷哼從身側響起喘蟆,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤现诀,失蹤者是張志新(化名)和其女友劉穎夷磕,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體仔沿,經...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年尺棋,在試婚紗的時候發(fā)現自己被綠了封锉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡膘螟,死狀恐怖成福,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情荆残,我是刑警寧澤奴艾,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站内斯,受9級特大地震影響蕴潦,放射性物質發(fā)生泄漏。R本人自食惡果不足惜俘闯,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一潭苞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧真朗,春花似錦此疹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至旗扑,卻和暖如春蹦骑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肩豁。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工脊串, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人清钥。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓琼锋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親祟昭。 傳聞我的和親對象是個殘疾皇子缕坎,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內容

  • STL部分 1.STL為什么廣泛被使用 C++ STL 之所以得到廣泛的贊譽,也被很多人使用篡悟,不只是提供了像vec...
    杰倫哎呦哎呦閱讀 4,328評論 0 9
  • 什么是容器 首先谜叹,我們必須理解一下什么是容器匾寝,在C++ 中容器被定義為:在數據存儲上,有一種對象類型荷腊,它可以持有其...
    Jack_Cui閱讀 479評論 0 2
  • 標簽(空格分隔): STL 運用STL艳悔,可以充分利用該庫的設計,讓我為簡單而直接的問題設計出簡單而直接的解決方案女仰,...
    認真學計算機閱讀 1,483評論 0 10
  • 容器的概念所謂STL容器猜年,即是將最常運用的一些數據結構(data structures)實現出來。容器是指容納特定...
    飯飯H閱讀 385評論 0 0
  • #1.順序容器概述 #2.容器庫概覽迭代器容器類型成員begin和end成員容器定義和初始化賦值和swap容器大小...
    MrDecoder閱讀 1,228評論 0 1