搞定技術面試:那些你可能不知道的 vector 和 array 的區別

搞定技術面試:那些你可能不知道的 vector 和 array 的區別

最近幾年,計算機工作越發難找,你必須比其他人瞭解的更多,纔能有更多的機會找到一個更好的工作。

C++ 標準庫(STL)是很多C++面試中都會問到的問題,很多很多問題會關於 Vector 的空間分配、動態增長之類的問題,那麼你瞭解 STL 中那些順序容器的區別與聯繫嗎?
你知道在什麼情況選用什麼容器嗎?

先說結論,一般情況選擇 vector 是很好的選擇,如果你的程序目標有如下特點時,纔可能需要換用別的容器:

  • 有很多小元素、空間額外開銷比較重要,不要使用 list 和 forward_list;
  • 程序要求隨機訪問,選擇 vector 和 deque;
  • 程序經常在中間插入元素,可以選擇 list 和 forward_list;
  • 程序只在頭尾插入元素,不常在中間插入元素,選擇 deque;
  • 程序一開始插入時會在中間插入元素,但之後的使用過程中基本不在中間插入元素,先用 list 處理輸入場景,再用 vector 拷貝 list 的數據,處理後續使用。

整體介紹

所有的順序容器都具有可以快速按順序訪問元素的能力,但每種容器在具體的實現上又有些區別。

順序容器類型 含義 特點
vector 可變大小數組 隨機訪問快、尾部插入元素快、其他位置插入、刪除元素慢
deque 雙端隊列 隨機訪問快、頭尾插入元素快
list 雙向鏈表 只支持雙向順序訪問、在任何位置插入、刪除元素都很快
forward_list 單向鏈表 只支持從前往後的單向順序訪問、在任何位置插入刪除元素都很快
array 固定大小數組 隨機訪問快、容器大小固定不支持插入刪除元素
string 字符串,類似vector,專門保存字符、隨機訪問快、在尾部插入刪除元素快

按類型介紹

vector string

vector 和 string 將元素保存在連續的內存空間中,分配一段連續的內存空間進行存儲,其迭代器採用 C++ 指針即可,因此其支持隨機訪問和存儲,支持下標操作符,節省空間。但是其在分配的內存不夠的情況下,需要對容器整體進行重新分配、拷貝和釋放等操作(空間的動態增長),而且在 vector 和 string 中間插入或刪除元素效率很低。

在這裏插入圖片描述
vector的內存分配實現原理:STL內部實現時,首先分配一個非常大的內存空間預備進行存儲,即capacity()函數返回的大小,當超過此分配的空間時再整體重新放分配一塊內存存儲(VS6.0是兩倍,VS2005是1.5倍),所以這給人以vector可以不指定vector即一個連續內存的大小的感覺。通常此默認的內存分配能完成大部分情況下的存儲。

擴充空間(不論多大)都應該這樣做:

  1. 配置一塊新空間
  2. 將舊元素一一搬往新址
  3. 把原來的空間釋放還給系統

list forward_list

list 和 forward_list 是以節點形式來存放數據,使用的是非連續的內存空間來存放數據,因此,在其內部插入和刪除元素的時間複雜度都是O(1),但是其不支持隨機訪問和存取,不支持下標;因爲每個結點需要額外空間存儲連接的情況,他們比 vector 佔用的內存要多很多。
在這裏插入圖片描述

list 是非連續存儲結構,具有雙鏈表結構,每個元素維護一對前向和後向指針,因此支持前向/後向遍歷。支持高效的隨機插入/刪除操作,但隨機訪問效率低下,且由於需要額外維護指針,開銷也比較大。每一個結點都包括一個信息快Info、一個前驅指針Pre、一個後驅指針Post。可以不分配必須的內存大小方便的進行添加和刪除操作。使用的是非連續的內存空間進行存儲。

forward_list 底層實現上是單鏈表,且實質上無任何多餘開銷,與 list 相比,此容器在不需要雙向迭代時提供更有效地利用空間的存儲。在鏈表內或跨數個鏈表添加、移除和移動元素,不會非法化當前指代鏈表中其他元素的迭代器。forward_list 的迭代器不支持iter--操作,即不支持反向迭代;同時 forward_list 也不支持size()操作。

deque

vector是一個單向開口的容器,deque則是一個雙向開口的容器,所謂雙向開口就是再頭尾兩端均可以做元素的插入和刪除操作。

在這裏插入圖片描述
deque 在空間增長上與 vector 不同,它是動態的以分段的連續空間組合而成,隨時可以增加一段空間連接起來。
因此,爲了管理多段連接,deque有中控器的概念,此處實現上詳細情況的請參見《STL源碼剖析》

array

array 與內置數組類似,大小是固定的,因此不支持增加元素、刪除元素以及改變容器大小的功能。
在使用 array 時,必須同時指定元素類型和大小array<int,20>

此容器是一個聚合類型,其語義等同於保有一個 C 風格數組 T[N] 作爲其唯一非靜態數據成員的結構體。該結構體結合了 C 風格數組的性能、可訪問性與容器的優點,比如可獲取大小、支持賦值、隨機訪問迭代器等。

迭代器 Iterator

迭代器的範圍都是左開右閉,理解爲數學上的區間則是 [xx.begin(), xx.end()),左邊是可以達到的,右邊是達不到的。

Reference

  1. C++ Primer 5th
  2. STL 源碼剖析
  3. Cppreference
  4. CSDN:C++三種容器:list、vector和deque的區別
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章