一、前言
1. 總的來說,STL包括幾個部分:容器,算法(泛型算法),迭代器三個主要部分(當然還包含仿函數,適配器等其他部分)
2. 容器包含兩大類:順序容器、關聯容器
順序容器 元素是按它們在容器中的位置來順序保存和訪問的。
- 3 種 -- 可變長動態數組 vector、雙端隊列 deque、雙向鏈表 list
關聯容器 元素是按關鍵字來保存和訪問的。
- 4 種 -- set、multiset、map、multimap
- 默認情況下,關聯容器中的元素是從小到大排序(或按關鍵字從小到大排序)
其他
- 3 種容器適配器:棧 stack、隊列 queue、優先級隊列 priority_queue
二、順序容器
1、vector
其底層數據結構是數組,由於數組的特點,vector也具有以下特性:
a)、O(1)時間的快速訪問;
b)、順序存儲,所以插入到非尾結點位置所需時間複雜度爲O(n),刪除也一樣;
c)、擴容規則:
當我們新建一個vector的時候,會首先分配給他一片連續的內存空間,如
std::vector<int> vec
,當通過push_back向其中增加元素時,如果初始分配空間已滿,就會引起vector擴容,其擴容規則跟編譯器有關,1.5 倍或 2 倍擴容:
首先重新申請一個 1.5 / 2 倍大的內存空間;
然後將原空間的內容拷貝過來;
最後將原空間內容進行釋放,將內存交還給操作系統
d)、注意事項:
根據vector的插入和刪除特性,以及擴容規則,我們在使用vector的時候要注意,在插入位置和刪除位置之後的所有迭代器和指針引用都會失效,同理,擴容之後的所有迭代器指針和引用也都會失效。
2、list deque
list的底層數據結構爲雙向鏈表,特點是支持快速的增刪。內存地址不連續
queue爲單向隊列,爲先入先出原則。由多個連續內存塊構成,deque是 list 和 vector 的兼容
deque爲雙向隊列,其對比queue可以實現在頭尾兩端高效的插入和刪除操作
3、下面是選擇順序容器類型的一些準則
1. 如果我們需要隨機訪問一個容器則 vector 要比 list 好得多 。
2. 如果我們已知要存儲元素的個數則 vector 又是一個比 list 好的選擇。
3. 如果我們需要的不只是在容器兩端插入和刪除元素則list顯然要比 vector 好
4. 除非我們需要在容器首部插入和刪除元素否則 vector 要比 deque 好。
5. 如果只在容易的首部和尾部插入數據元素,則選擇 deque.
6. 如果只需要在讀取輸入時在容器的中間位置插入元素,然後需要隨機訪問元素,則可考慮輸入時將元素讀入到一個 List容器,接着對此容器重新排序,使其適合順序訪問,然後將排序後的 list 容器複製到一個 vector 容器中
三、關聯容器
1、map & multimap & unordered_map & unordered_multimap
map與multimap底層數據結構
- 有序的
- map 一對一 key-value
- multimap 多對多 key-value
- 區別在於,multimap允許關鍵字重複,而map不允許重複。
- 底層數據結構均爲紅黑樹,關於紅黑樹的理解可以參考教你透徹瞭解紅黑樹一文。
- 根據紅黑樹的原理,map與multimap可以實現 O(lgn) 的查找,插入和刪除。
- 紅黑樹提高了運行效率,但是因爲每一個節點都需要額外保存父節點、孩子節點和紅/黑性質,使得每一個節點都佔用大量的空間
unordered_map 與unordered_multimap底層數據結構
- 無序的
- 底層實現爲 hash table,因此其查找速度非常的快,理論( 理想無碰撞的情況下 ) 上達到了O(n)
- 存儲方式 根據 散列值組織成桶 以允許通過它們的鍵值直接快速訪問單個元素(具有常數平均時間複雜度)
- 每個桶保存零個或多個元素,容器的性能依賴於哈希函數的質量和桶的數量和大小
- 哈希表的建立比較耗費時間
【注】:mulitimap
如果multimap中有多個元素具有相同的關鍵字,則這些關鍵字在容器中會相鄰存儲
獲取多個相同關鍵字對應值的方法 如下:
multimap<int, string> mMap; typedef multimap<int, string>::iterator int_multimap; // equal_range(key) 返回 key 對應的所有元素的起始和結束迭代器. pair<int_multimap, int_multimap> p = mMap.equal_range(4); for (int_multimap k = p.first; k != p.second; k++) { cout << k->second << endl; }
//authors是一個multimap容器 string search_item("Alain"); int numbers=authors.count(search_item); auto it=authors.find(search_item); while(numbers) { cout<<iter->second<<endl; ++it; numbers--; }
相關接口操作
1.桶接口
m.bucket_count() // 正在使用的桶的數目 m.max_bucket_count() // 容器能容納的最多的桶的數量 m.bucket_size(n) // 第n個桶中有多少個元素 m.bucket(k) // 關鍵字爲k的元素在哪個桶
2.桶迭代
local_iterator // 可以用來訪問桶中元素的迭代器類型 const_local_iterator // 桶迭代器的const版本 m.begin(n)、m.end(n) // 桶n的首元素迭代器和尾後迭代器(n是什麼類型?) m.cbegin(n)、m.cend(n) // 與前兩個函數類似,但返回const_local_iterator
3.哈希策略
//每個桶的平均元素數量,返回float值 m.load_factor() //m試圖維護的平均桶大小,返回float值,要求創建的新桶的load_factor<=max_load_factor m.max_load_factor() //重新存儲,使得bucket_count>=n,且bucket_count>size/max_load_factor m.rehash(n) //重新存儲,使得m可以保存n個元素且不必rehash m.reserve(n)
2、set & multiset & unordered_set & unordered_multiset
set 系與 map 系的區別
- map中存儲的是<key-value>,而 set 可以理解爲關鍵字即值,即只保存關鍵字的容器
set & multiset底層數據結構
- 紅黑樹,能實現O(lgn)的查找,插入,刪除操作
unordered_set & unordered_multiset
- 底層實現爲hash table
注:所有 有序 關聯容器 數據是按 關鍵字的 字典順序 進行存儲存放的
四、其他
1、 priority_queue 優先級隊列
優先級隊列相當於一個有權值的單向隊列queue,在這個隊列中,所有元素是按照優先級排列的。
priority_queue根據 堆 的處理規則來調整元素之間的位置,關於堆的原理,可以參考堆;
根據堆的特性,優先級隊列實現了取出最大最小元素時間複雜度爲 O(1) ,對於插入和刪除,其最壞情況爲O(lgn)。
詳細用法見 https://blog.csdn.net/xiaoquantouer/article/details/52015928