STL 序列式容器(
vector
、deque
、list
、array
、forward_list
)的核心特征是按插入順序存儲元素(元素的邏輯順序與物理存儲順序一致)
?vector
下圖是底層原理 具體點擊鏈接vector介紹
deque(雙端隊列)
在 C++ STL 中,deque
(Double-Ended Queue,雙端隊列)是一種支持兩端高效插入 / 刪除的序列式容器,底層通過 “分段動態數組 + 中控數組” 的結構實現,兼顧了隨機訪問能力和雙端操作效率。以下從核心特性、底層原理、常用接口、適用場景等方面全面解析?deque
:
一、核心特性
-
雙端高效操作
- 頭部(
front
)和尾部(back
)的插入(push_front
/push_back
)、刪除(pop_front
/pop_back
)操作均為?O (1) 時間復雜度(無需像?vector
?那樣移動大量元素,也無需像?list
?那樣分配節點)。
- 頭部(
-
支持隨機訪問
- 提供下標運算符(
[]
)和?at()
?成員函數,可直接訪問指定位置的元素,時間復雜度?O(1)(優于?list
?的 O (n),但底層實現比?vector
?復雜)。
- 提供下標運算符(
-
動態擴容
- 容量不足時會自動擴容,但擴容邏輯比?
vector
?更靈活:vector
?擴容需分配新的連續內存并拷貝所有元素(O (n) 開銷),而?deque
?只需新增一個 “分段數組” 并更新中控數組(避免大規模拷貝,平均擴容開銷更低)。
- 容量不足時會自動擴容,但擴容邏輯比?
-
非連續內存存儲
- 底層并非連續內存(與?
vector
?不同),而是由多個小型連續內存塊(分段數組)和一個 “中控數組”(存儲各分段數組的地址)組成,通過中控數組實現對分段的管理,對外表現為 “連續的元素序列”。
- 底層并非連續內存(與?
二、底層原理(為什么能兼顧雙端操作和隨機訪問?)
deque
?的底層結構可拆解為兩部分,理解這部分能更清晰其特性來源:
-
分段數組(Buffer)
- 每個分段數組是固定大小的連續內存塊(例如默認 512 字節),用于存儲實際的元素;
- 分段數組的大小可通過編譯器宏(如?
_DEQUE_BUF_SIZE
)調整,也可在定義?deque
?時通過模板參數指定。
-
中控數組(Map)
- 本質是一個 “指針數組”,每個元素指向一個分段數組;
- 中控數組會預留一定的空閑位置(頭部和尾部),當頭部需要插入元素且當前首分段已滿時,直接在中控數組頭部新增一個分段指針;尾部同理,避免中控數組頻繁擴容。
訪問元素的邏輯:
當通過下標?i
?訪問?deque
?元素時,底層會先計算?i
?所在的 “分段索引”(i / 分段大小
)和 “分段內偏移”(i % 分段大小
),再通過中控數組找到對應的分段數組,最后通過偏移獲取元素 —— 這一過程是 O (1),因此支持隨機訪問。
三、常用成員函數(核心接口)
deque
?的接口與?vector
?類似,但新增了雙端操作的接口,以下是高頻使用的成員函數:
類別 | 成員函數 | 功能描述 |
---|---|---|
構造 / 析構 | deque() | 默認構造空的?deque |
deque(n, val) | 構造包含?n ?個?val ?的?deque | |
deque(beg, end) | 從迭代器范圍?[beg, end) ?構造?deque (如從?vector ?或?string ?初始化) | |
雙端操作 | push_front(val) | 在頭部插入元素?val (O(1)) |
push_back(val) | 在尾部插入元素?val (O(1)) | |
pop_front() | 刪除頭部元素(O (1),需確保?deque ?非空) | |
pop_back() | 刪除尾部元素(O (1),需確保?deque ?非空) | |
元素訪問 | operator[](i) | 訪問下標?i ?處的元素(無越界檢查,越界行為未定義) |
at(i) | 訪問下標?i ?處的元素(有越界檢查,越界拋?out_of_range ?異常) | |
front() | 獲取頭部元素(O (1)) | |
back() | 獲取尾部元素(O (1)) | |
容量操作 | size() | 返回元素個數(O (1)) |
empty() | 判斷是否為空(O (1),空返回?true ) | |
resize(n, val) | 調整元素個數為?n :不足補?val ,多余刪除 | |
clear() | 清空所有元素(O (n),元素析構,但中控數組和分段數組可能保留以復用) | |
迭代器 | begin() /end() | 獲取首元素 / 尾后元素的迭代器(支持隨機訪問,可?++ /-- /+n /-n ) |
rbegin() /rend() | 獲取反向迭代器(從尾部向頭部遍歷) |
四、適用場景(什么時候用?deque
?)
deque
?的特性決定了它適合 “需要雙端操作 + 隨機訪問” 的場景,典型場景包括:
-
實現隊列(Queue)或雙端隊列
- STL 的?
queue
?容器適配器默認以?deque
?為底層容器(因為?queue
?需支持?push_back
?和?pop_front
,deque
?這兩個操作都是 O (1),優于?vector
?的?pop_front
(O(n)))。
- STL 的?
-
頻繁在兩端插入 / 刪除,且需要隨機訪問
- 例如:滑動窗口算法(需在窗口兩端添加 / 移除元素,同時訪問窗口內任意位置元素)、日志存儲(新日志追加到尾部,舊日志從頭部刪除,偶爾需查詢中間日志)。
-
替代?
vector
?避免大規模擴容開銷- 當?
vector
?存儲大量元素時,擴容會拷貝所有元素,開銷較大;而?deque
?擴容只需新增分段,適合元素數量動態增長且規模較大的場景(但隨機訪問效率略低于?vector
,需權衡)。
- 當?
五、與其他容器的對比(vector
?vs?list
?vs?deque
)
特性 | vector | list | deque |
---|---|---|---|
底層結構 | 連續動態數組 | 雙向鏈表 | 分段數組 + 中控數組 |
隨機訪問([] /at ) | 支持(O (1)) | 不支持(O (n)) | 支持(O (1)) |
頭部插入 / 刪除 | 不支持頭部插入,可以刪除 | 高效(O (1)) | 高效(O (1)) |
尾部插入 / 刪除 | 高效(O (1),擴容時 O (n)) | 高效(O (1)) | 高效(O (1)) |
中間插入 / 刪除 | 不高效(O (n)) | 高效(O (1),找位置 O (n)) | 不高效(O (n)) |
內存利用率 | 高(連續內存,緩存友好) | 低(節點有指針開銷) | 中等(分段有少量浪費) |
擴容開銷 | 高(拷貝所有元素) | 低(僅分配新節點) | 低(新增分段) |
六、使用示例(代碼演示)
#include <iostream>
#include <deque>
#include <algorithm> // 用于 sort 等算法int main() {// 1. 構造 deque 并初始化std::deque<int> dq1; // 空 dequestd::deque<int> dq2(5, 10); // 5個10:[10,10,10,10,10]std::deque<int> dq3(dq2.begin(), dq2.end()); // 從 dq2 復制:[10,10,10,10,10]// 2. 雙端插入元素dq1.push_back(20); // 尾部插入:[20]dq1.push_front(10); // 頭部插入:[10,20]dq1.push_back(30); // 尾部插入:[10,20,30]// 3. 隨機訪問和遍歷std::cout << "dq1[1] = " << dq1[1] << std::endl; // 輸出 20(隨機訪問)std::cout << "dq1 遍歷:";for (int i = 0; i < dq1.size(); ++i) {std::cout << dq1[i] << " "; // 10 20 30}std::cout << std::endl;// 4. 雙端刪除元素dq1.pop_front(); // 刪除頭部:[20,30]dq1.pop_back(); // 刪除尾部:[20]// 5. 排序(支持隨機訪問迭代器,可直接用 sort 算法)std::deque<int> dq4 = {3, 1, 4, 2};std::sort(dq4.begin(), dq4.end()); // 排序后:[1,2,3,4]std::cout << "排序后 dq4:";for (auto val : dq4) {std::cout << val << " "; // 1 2 3 4}return 0;
}
七、注意事項
- 避免中間插入 / 刪除:
deque
?中間插入 / 刪除需要移動該位置兩側的元素(O (n) 時間),效率低,若需頻繁中間操作,優先用?list
。 - 迭代器穩定性:
deque
?的迭代器在擴容時可能失效(中控數組擴容會導致分段指針地址變化),但在兩端插入 / 刪除時,除了首分段和尾分段的迭代器,其他分段的迭代器仍有效(與?vector
?所有迭代器失效不同)。 - 不適合存儲大對象:每個分段數組存儲元素,若元素體積大,分段數量會減少,但隨機訪問邏輯不變,不過內存碎片可能增加(需結合實際場景權衡)。
總之,deque
?是 STL 中 “平衡雙端操作和隨機訪問” 的容器,在需要頻繁操作兩端且需隨機訪問的場景中,是比?vector
?和?list
?更優的選擇。
list(
雙向鏈表)
在 C++ STL 中,std::list
?是一種雙向鏈表(雙向非循環鏈表)?容器,其元素通過節點間的指針連接,不要求內存連續。這種結構使其在任意位置的插入和刪除操作上具有獨特優勢,以下從核心特性、底層原理、常用接口和適用場景等方面詳細解析:
一、核心特性
-
雙向鏈表結構
每個節點包含:- 數據域(存儲元素值)
- 前驅指針(指向當前節點的前一個節點)
- 后繼指針(指向當前節點的后一個節點)
首節點的前驅指針和尾節點的后繼指針均為?nullptr
,不形成循環。
-
高效的插入與刪除
- 在任意位置(頭部、尾部、中間)插入或刪除元素的時間復雜度為?O(1)(只需修改相鄰節點的指針,無需移動其他元素)。
- 但查找目標位置需要遍歷鏈表,時間復雜度為?O(n),因此 “查找 + 插入 / 刪除” 的整體復雜度為 O (n)。
-
不支持隨機訪問
無法通過下標([]
)直接訪問元素,必須從首節點或尾節點開始遍歷(通過迭代器?++
/--
?移動),訪問第 n 個元素的時間復雜度為 O (n)(這是與?vector
、deque
?的核心區別)。 -
內存動態分配
元素在堆上逐個分配內存,節點間無需連續,因此不會像?vector
?那樣因擴容導致大規模內存拷貝,但存在額外的指針內存開銷(每個節點兩個指針)。
二、底層原理(為何插入刪除高效?)
list
?的高效插入 / 刪除源于其鏈表結構:
- 當已知插入 / 刪除位置的迭代器時,操作僅需 3 步:
- 創建新節點(插入時)或標記待刪除節點(刪除時);
- 修改前一個節點的后繼指針,指向新節點(插入)或下一個節點(刪除);
- 修改新節點(插入)或下一個節點的前驅指針,指向合適的節點。
- 整個過程無需移動其他元素,僅涉及指針修改,因此效率極高。
例如,在節點?A
?和?B
?之間插入節點?C
:
原鏈表:A <-> B
插入后:A <-> C <-> B
(僅需修改 A 的后繼指針和 B 的前驅指針)
三、常用成員函數(核心接口)
list
?提供了豐富的接口,尤其針對鏈表特性優化了插入、刪除和移動操作:
類別 | 成員函數 | 功能描述 |
---|---|---|
構造 / 析構 | list() | 默認構造空鏈表 |
list(n, val) | 構造包含?n ?個?val ?的鏈表 | |
list(beg, end) | 從迭代器范圍?[beg, end) ?構造鏈表(如從?vector ?或數組初始化) | |
兩端操作 | push_front(val) | 在頭部插入元素(O (1)) |
push_back(val) | 在尾部插入元素(O (1)) | |
pop_front() | 刪除頭部元素(O (1),需確保鏈表非空) | |
pop_back() | 刪除尾部元素(O (1),需確保鏈表非空) | |
任意位置操作 | insert(pos, val) | 在迭代器?pos ?指向的位置前插入?val ,返回新元素的迭代器(O (1)) |
erase(pos) | 刪除迭代器?pos ?指向的元素,返回下一個元素的迭代器(O (1)) | |
erase(beg, end) | 刪除迭代器范圍?[beg, end) ?內的元素,返回下一個元素的迭代器(O (n)) | |
元素訪問 | front() | 獲取頭部元素的引用(O (1)) |
back() | 獲取尾部元素的引用(O (1)) | |
鏈表操作 | clear() | 清空所有元素(O (n)) |
size() | 返回元素個數(O (1),C++11 后支持,之前版本需遍歷計數) | |
empty() | 判斷是否為空(O (1)) | |
sort() | 對鏈表排序(內部實現為歸并排序,O (n log n),不支持?std::sort ?因為需要隨機訪問迭代器) | |
reverse() | 反轉鏈表(O (n)) | |
splice(pos, list2) | 將鏈表?list2 ?的所有元素移動到當前鏈表?pos ?位置前(O (1),無元素拷貝) |
下面是list
容器特有的操作及其示例,所有操作將在同一段代碼中展示:
#include <iostream>
#include <list>
#include <algorithm>using namespace std;int main() {// 創建兩個鏈表list<int> list1 = {3, 1, 4, 1, 5};list<int> list2 = {2, 7, 1, 8};cout << "初始鏈表:" << endl;cout << "list1: ";for (int num : list1) cout << num << " "; // 3 1 4 1 5cout << "\nlist2: ";for (int num : list2) cout << num << " "; // 2 7 1 8cout << endl << endl;// 1. sort() - 鏈表排序list1.sort();cout << "1. list1排序后: ";for (int num : list1) cout << num << " "; // 1 1 3 4 5cout << endl;// 2. unique() - 移除連續重復元素(需先排序)list1.unique();cout << "2. list1去重后: ";for (int num : list1) cout << num << " "; // 1 3 4 5cout << endl;// 3. reverse() - 反轉鏈表list1.reverse();cout << "3. list1反轉后: ";for (int num : list1) cout << num << " "; // 5 4 3 1cout << endl;// 4. merge() - 合并兩個已排序的鏈表(會修改原鏈表)list1.sort(); // 先確保list1有序list2.sort(); // 先確保list2有序list1.merge(list2); // 合并到list1,list2會被清空cout << "4. 合并后list1: ";for (int num : list1) cout << num << " "; // 1 1 2 3 4 5 7 8cout << "\n 合并后list2: ";for (int num : list2) cout << num << " "; // 空cout << endl;// 5. splice() - 轉移元素(從另一個鏈表移動元素)list<int> list3 = {10, 20, 30};auto it = list1.begin();advance(it, 3); // 移動迭代器到第4個元素位置list1.splice(it, list3, list3.begin(), list3.end()); // 將list3所有元素插入到list1的指定位置cout << "5. splice后list1: ";for (int num : list1) cout << num << " "; // 1 1 2 10 20 30 3 4 5 7 8cout << "\n splice后list3: ";for (int num : list3) cout << num << " "; // 空cout << endl;// 6. remove() - 移除所有指定值的元素list1.remove(1); // 移除所有值為1的元素cout << "6. 移除所有1后: ";for (int num : list1) cout << num << " "; // 2 10 20 30 3 4 5 7 8cout << endl;// 7. remove_if() - 移除滿足條件的元素(例如移除偶數)list1.remove_if([](int n) { return n % 2 == 0; });cout << "7. 移除所有偶數后: ";for (int num : list1) cout << num << " "; // 3 5 7cout << endl;return 0;
}
四、適用場景(什么時候用?list
?)
list
?適合以下場景:
-
頻繁在任意位置插入 / 刪除元素
例如:實現鏈表式數據結構(如鄰接表)、日志系統(需在中間插入修正記錄)、 undo/redo 操作棧(頻繁在頭部插入歷史記錄)。 -
元素數量動態變化大,且無需隨機訪問
當不需要通過下標訪問元素,僅需順序遍歷,且增刪操作頻繁時,list
?比?vector
(中間增刪效率低)和?deque
(中間增刪效率低)更合適。 -
需要高效移動元素塊
通過?splice
?成員函數可以 O (1) 時間移動整個鏈表或子鏈表(無元素拷貝,僅修改指針),適合實現鏈表合并、拆分等操作。
五、與?vector
、deque
?的對比
特性 | list | vector | deque |
---|---|---|---|
底層結構 | 雙向鏈表 | 連續動態數組 | 分段數組 + 中控數組 |
隨機訪問([] ) | 不支持(O (n)) | 支持(O (1)) | 支持(O (1)) |
任意位置插入 / 刪除 | O (1)(已知位置) | O (n)(需移動元素) | O (n)(需移動元素) |
內存連續性 | 不連續 | 連續 | 分段連續 |
內存開銷 | 高(節點含指針) | 低(僅存儲元素) | 中(分段管理) |
迭代器類型 | 雙向迭代器 | 隨機訪問迭代器 | 隨機訪問迭代器 |
適用場景 | 頻繁任意位置增刪 | 頻繁隨機訪問 | 頻繁雙端操作 + 隨機訪問 |
六、使用示例(代碼演示)
#include <iostream>
#include <list>
#include <algorithm> // 用于 find 等算法int main() {// 1. 構造 list 并初始化std::list<int> lst1; // 空鏈表std::list<int> lst2(3, 5); // 3個5:[5,5,5]std::list<int> lst3(lst2.begin(), lst2.end()); // 從 lst2 復制:[5,5,5]// 2. 插入元素lst1.push_back(10); // 尾部插入:[10]lst1.push_front(20); // 頭部插入:[20,10]auto it = lst1.begin(); // it 指向 20++it; // it 指向 10lst1.insert(it, 30); // 在 10 前插入 30:[20,30,10]// 3. 遍歷元素(只能通過迭代器或范圍 for)std::cout << "lst1 元素:";for (int val : lst1) {std::cout << val << " "; // 20 30 10}std::cout << std::endl;// 4. 刪除元素lst1.pop_front(); // 刪除頭部:[30,10]it = std::find(lst1.begin(), lst1.end(), 30); // 查找 30 的迭代器if (it != lst1.end()) {lst1.erase(it); // 刪除 30:[10]}// 5. 鏈表特有操作std::list<int> lst4 = {3, 1, 2};lst4.sort(); // 排序:[1,2,3]lst4.reverse(); // 反轉:[3,2,1]std::cout << "lst4 排序反轉后:";for (int val : lst4) {std::cout << val << " "; // 3 2 1}return 0;
}
七、注意事項
- 迭代器有效性:
list
?的迭代器在插入元素后仍有效(只需調整指針,節點地址不變);刪除元素后,只有指向被刪除節點的迭代器失效,其他迭代器仍可使用(這是?list
?的重要優勢)。 - 不支持?
std::sort
:std::sort
?要求隨機訪問迭代器,而?list
?是雙向迭代器,因此必須使用自身的?sort()
?成員函數。 - 緩存不友好:由于元素內存不連續,CPU 緩存命中率低,遍歷速度通常慢于?
vector
(即使兩者時間復雜度均為 O (n))。
總之,list
?是針對 “頻繁任意位置增刪” 優化的容器,在不需要隨機訪問的場景中,能顯著提升操作效率。
---------------------------------------------------------------------------------------------------------------------------------
deque插入(insert)的底層原理
通過__index
判斷插入點位置,選擇移動元素更少的方向(頭部或尾部),體現 “短路徑優先” 的優化思想。這段代碼的注釋清晰展現了deque
中間插入的優化邏輯,即通過巧妙利用頭尾操作的高效性,減少元素移動的數量,從而提升插入性能。
// 模板函數定義:在deque的中間位置插入單個元素的輔助函數
// 返回值:插入后新元素的迭代器
// 參數:__pos-插入位置迭代器;__x-要插入的元素值
template <class _Tp, class _Alloc>
typename deque<_Tp, _Alloc>::iterator
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x)
{// 計算插入點__pos相對于起始位置_M_start的偏移量(邏輯索引)// 用于判斷插入點更靠近頭部還是尾部difference_type __index = __pos - _M_start;// 復制要插入的元素(避免原元素被意外修改,確保值的穩定性)value_type __x_copy = __x;// 判斷插入點是否更靠近頭部(距離頭部比距離尾部近)// 采用"短路徑優先"策略,減少需要移動的元素數量if (size_type(__index) < this->size() / 2) {// 分支1:插入點靠近頭部,從頭部方向移動元素// 在頭部插入一個當前頭部元素的副本(利用deque頭部插入高效的特性)// 此時頭部會有一個重復元素,后續會通過移動覆蓋push_front(front());// 定義迭代器:__front1指向新插入的頭部副本元素iterator __front1 = _M_start;++__front1;// __front2指向__front1的下一個元素(原頭部元素)iterator __front2 = __front1;++__front2;// 重新定位插入點__pos:因頭部插入可能導致迭代器失效,通過索引重新計算__pos = _M_start + __index;// __pos1指向插入點的下一個元素(需要移動的起始位置)iterator __pos1 = __pos;++__pos1;// 將[__front2, __pos1)范圍內的元素復制到__front1開始的位置// 效果:從頭部方向將元素向后移動一個位置,為新元素騰出空間copy(__front2, __pos1, __front1);}else {// 分支2:插入點靠近尾部,從尾部方向移動元素// 在尾部插入一個當前尾部元素的副本(利用deque尾部插入高效的特性)// 此時尾部會有一個重復元素,后續會通過移動覆蓋push_back(back());// 定義迭代器:__back1指向新插入的尾部副本元素iterator __back1 = _M_finish;--__back1;// __back2指向__back1的前一個元素(原尾部元素)iterator __back2 = __back1;--__back2;// 重新定位插入點__pos:因尾部插入可能導致迭代器失效,通過索引重新計算__pos = _M_start + __index;// 將[__pos, __back2]范圍內的元素從后向前復制到__back1方向// 效果:從尾部方向將元素向后移動一個位置,為新元素騰出空間copy_backward(__pos, __back2, __back1);}// 在騰出的插入位置放入新元素的副本*__pos = __x_copy;// 返回指向新插入元素的迭代器return __pos;
}
需要注意的是: vector
?的?insert
?操作可能導致迭代器失效,這是由?vector
?底層連續內存的特性決定的。當插入元素引發內存重新分配或元素移動時,原有的迭代器、指針或引用可能指向無效內存,使用它們會導致未定義行為(如程序崩潰、數據錯誤)。
如何避免迭代器失效?
-
使用?
insert
?的返回值更新迭代器
vector::insert
?會返回一個新的迭代器,指向插入的新元素。用這個返回值更新原迭代器,可避免失效:auto it = vec.begin() + 1; // 插入元素并獲取新迭代器 it = vec.insert(it, 99); // it 現在指向新插入的99,有效
-
提前預留足夠容量(
reserve
)
若已知插入元素的數量,先用?reserve(n)
?預留足夠容量,避免插入時觸發擴容:vec.reserve(100); // 預留100個元素的空間 // 后續插入不超過100個元素時,不會觸發擴容
-
插入后重新獲取迭代器
若無法提前預留容量,插入后通過索引或?begin()
?重新計算迭代器:vec.insert(vec.begin() + 1, 99); auto it = vec.begin() + 1; // 重新獲取,有效
總結
從這個表格中,我們可以了解到 C++ 標準庫中三種主要序列容器(vector
、deque
、list
)的接口特性和功能差異,主要信息如下:
1. 容器基本信息
- 三種種容器對應的頭文件:
vector
對應<vector>
,deque
對應<deque>
,list
對應<list>
。 - 這三種容器都屬于序列容器,遵循線性存儲結構。
2. 通用成員函數
三種容器都支持的核心操作(相同點):
- 構造 / 析構:都有構造函數
(constructor)
和析構函數(destructor)
。 - 賦值操作:都支持
operator=
(賦值運算符)和assign
(批量賦值)。 - 迭代器:都支持
begin
/end
(正向迭代器)、rbegin
/rend
(反向迭代器),以及帶c
前綴的常量迭代器(如cbegin
/cend
)。 - 元素訪問:都支持
front
(訪問首元素)和back
(訪問尾元素)。 - 容器屬性:都支持
empty
(判斷是否為空)、size
(當前元素數量)、max_size
(最大可容納元素數)、resize
(調整容器大小)。 - 修改操作:都支持
clear
(清空容器)、insert
(插入元素)、emplace
(原位構造元素)、erase
(刪除元素)、push_back
(尾部插入)、emplace_back
(尾部原位構造)、pop_back
(尾部刪除)、swap
(交換容器內容)。 - 內存分配器:都支持
get_allocator
(獲取內存分配器)。
3. 容器特有差異
三種容器的獨特接口(不同點):
-
vector:
- 支持
at
(帶邊界檢查的下標訪問)和operator[]
(下標訪問)。 - 支持
data
(直接獲取底層數據指針)。 - 有
capacity
(當前容量)、reserve
(預留容量)、shrink_to_fit
(收縮容量至實際大小),體現其連續內存的特性。 - 不支持頭插
- 支持
-
deque:
- 支持
at
和operator[]
(下標訪問),但無data
(非連續內存)。 - 支持
shrink_to_fit
(C++11 后)。
- 支持
-
list(雙向鏈表):
- 不支持下標訪問(無
at
、operator[]
、data
)。 - 支持
push_front
(頭部插入)、emplace_front
(頭部原位構造)、pop_front
(頭部刪除),且效率很高(鏈表特性)。 - 有專屬操作:
merge
(合并鏈表)、splice
(轉移元素)、remove
(按值刪除)、remove_if
(按條件刪除)、reverse
(反轉鏈表)、unique
(去重)、sort
(排序),這些都是鏈表結構優化的操作。
- 不支持下標訪問(無
4. 容器選擇依據
從接口差異可推斷適用場景:
vector
:適合隨機訪問頻繁、尾部增刪為主的場景(連續內存,隨機訪問效率 O (1))。deque
:適合頭尾兩端頻繁增刪的場景(雙端隊列,兩端操作效率 O (1))。list
:適合任意位置頻繁插入 / 刪除的場景(鏈表結構,增刪效率 O (1),但隨機訪問效率低 O (n))。
這個表格本質上是三種容器接口兼容性和功能獨特性的對比,幫助開發者根據需求選擇合適的容器。