c++ 常用STL容器使用簡練總結

根據各容器的特點,作簡練的總結。

array


  • 帶有STL容器接口的static c-style array
  • 大小固定,無法通過增加或移除元素改變它的大小,即size()總是返回同一值
  • 提供常量時間的隨機訪問功能,但只有at()會檢查是否越界,其他調用若越界會導致未定義的行爲
  • 對於基礎類型,需要初始化:std::array<int, 4> a = {},否則初值不定
  • 使用data()成員函數直接轉化爲c-style array,但需要注意使用c array時既有問題

vector


  • 元素間有序,支持常量時間內的隨機訪問,是將元素置於dynamic array中加以管理的抽象
  • 適合於總是在容器末尾增加或刪除元素的情形,在中間插入或刪除元素的成本很高
  • 在使用之初,就reserve()足夠的內存,避免運行中內存分配,以提高效率。注意:reserve不通縮減容量,即,如果reserve的值小於capacity(),不會有任何動作
  • 如果關心空間佔用,可以使用c++11提供的shrink_to_fit()縮減容量,但即使這樣它也不保證capacity()==size()
  • 也可以使用swap()技巧縮減容量:std::vector<T>(v).swap(v);。注意,改變容量後所有的迭代器失效
  • vector沒有提供直接刪除“與某值相等”的所有元素的成員函數,可以使用算法來完成:v.erase(remove(v.begin(), v.end(), val), v.end())
  • vector與c-style array的相互轉換:v.data()。與array類似,需要注意相關潛在問題
  • 特別注意vector的使用,它的特化版本使用bit存放元素,所以其reference並非真正的lvalue,iterator也並非真正的隨機訪問迭代器

deque


  • 採用dynamic array管理,提供隨機訪問,接口與vector類似
  • 主要特點是首尾兩端都開放,可以快速地從首尾兩端進行插入和刪除
  • deque會釋放不再使用的內存區塊

list


  • 使用雙向鏈表管理元素,內部結構與array/vector/deque完全不同
  • 不支持隨機訪問,除非按節點遍歷。但訪問首尾兩個元素的速度很快
  • 在任意位置上的插入和刪除都是常量時間內完成,該操作也不會造成其他元素的索引及迭代器失效
  • 提供了較多的操作元素的成員函數,並提供異常安全性保證,即操作若不成功,則不作任何更改

forward list(c++11)


  • c++標準描述:我們希望forward_list和你自己手寫的C-style singly linked list相較之下沒有任何空間或時間上的額外開銷,任何性質如果與該目標相牴觸,我們就放棄該性質
  • 以單鏈表管理元素。相對於list,它內存佔用少,行動略快,但行爲受限,不能走回頭路
  • 只提供前向迭代器,不支持反向迭代。沒有指向最末元素的指針,不提供直接處理最末尾元素的成員函數
  • 不提供size,因爲增加該性質會增加額外的開銷

set/multiset


  • 會根據特定的排序準則自動將元素排序。set和multiset的不同之處是multiset允許元素重複,而set不允許
  • 排序採用“等價性”原則,默認爲less,區分less和equal是必要的
  • 通常採用平衡二叉樹存儲,它具有良好的查找性能(logn),但自動排序造成了一個限制:不通直接改變元素的值,因爲這會打亂原本正確的順序
  • 特別提供了用於查找的成員函數,它們比通用算法中相同功能的函數效率更高

map/multimap


  • 管理kye/value pair元素,根據key排序準則自動排序。map不允許重複的key,而multimap允許
  • 與set一樣,使用平衡二叉樹存儲,可以把set看成是key和value是同一對象的map
  • 同樣,不通直接修改key的值。另外,它也提供了用於查找的成員函數,效率較高
  • 注意,使用erase()刪除元素時,會使迭代器失效。應利用c++11中erase返回一個指向其後繼元素迭代器的性質避免錯誤
  • 注意下標操作與成員函數方式的區別,下標操作通常會先構造再賦值,效率略低,且易引用不易察覺的問題

無序容器(unordered_)


  • 包括unordered_set/unordered_multiset/unordered_map/unordered_multimap。它不會以某個規則排序,而是“隨意順序”
  • 一般以鏈式hash表爲基礎,查找效率較高。但是當允許元素重複的容器且重複值較多時,可能導致效率下降

小結


使用何種容器沒有絕對的標準,但選用適當的容器確實有助於提高程序性能。

當需要處理的元素數量很少時,線性算法通常對元素本身的處理過程更快。

一般規則如下:

  • 優先選用vector,它內部結構簡單,允許隨機訪問,處理速度也快
  • 經常在數據頭部和尾部增加刪除元素的情況,使用deque。當元素被刪除時,它能自動縮減內部內存使用量,對內存使用敏感時可以考慮
  • 經常在數據中部增刪元素時,使用list。它還可以在常量時間內將元素從A容器轉移到B容器
  • 經常需要根據某準則查找元素時,使用set/unordered_set
  • 需要處理key-value時,使用map/unordered_map

有時候,在特定的環境下,需要測試才能發現真正高效的容器。對於效率的極致追求者,這些付出是值得的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章