一、引言
STL(Standard Template Library)是 C++ 標準庫的核心組成部分,其中容器(Containers)?作為數據存儲的基礎組件,為開發者提供了豐富的數據結構選擇。本文將聚焦 STL 容器的核心類型,結合具體 C++ 代碼示例詳解其特性、用法及適用場景,幫助讀者在實際開發中精準選型。
二、序列容器(Sequence Containers)
序列容器按元素插入順序存儲數據,支持按位置訪問,是最常用的容器類型。
2.1?std::vector
:動態數組
特性:內存連續存儲,支持隨機訪問,尾部插入 / 刪除高效,中間插入 / 刪除開銷大。
適用場景:需要頻繁隨機訪問、尾部操作的場景(如存儲動態列表、緩存數據)。
代碼示例:
#include <iostream>
#include <vector>
using namespace std;int main() {// 1. 初始化方式vector<int> vec1; // 空vectorvector<int> vec2(5, 10); // 5個元素,每個初始化為10vector<int> vec3 = {1, 2, 3, 4, 5}; // 初始化列表// 2. 尾部插入元素vec1.push_back(6);vec1.push_back(7);// 3. 隨機訪問([]或at())cout << "vec3[2] = " << vec3[2] << endl; // 輸出3cout << "vec3.at(3) = " << vec3.at(3) << endl; // 輸出4(帶越界檢查)// 4. 遍歷元素(迭代器)cout << "vec3元素:";for (vector<int>::iterator it = vec3.begin(); it != vec3.end(); ++it) {cout << *it << " ";}cout << endl;// 5. 容量與大小cout << "vec3大小:" << vec3.size() << endl; // 5cout << "vec3容量:" << vec3.capacity() << endl; // 至少5(動態擴容)// 6. 中間插入元素(效率較低)vec3.insert(vec3.begin() + 2, 99); // 在索引2處插入99cout << "插入后vec3[2] = " << vec3[2] << endl; // 輸出99return 0;
}
2.2?std::list
:雙向鏈表
特性:非連續存儲,通過指針連接元素,任意位置插入 / 刪除高效,不支持隨機訪問。
適用場景:需要頻繁在中間插入 / 刪除元素的場景(如實現鏈表、隊列、鄰接表)。
代碼示例:
#include <iostream>
#include <list>
using namespace std;int main() {// 初始化列表list<int> lst = {3, 1, 4, 1, 5};// 1. 頭部/尾部操作lst.push_front(0); // 頭部插入0lst.push_back(6); // 尾部插入6// 2. 遍歷(不支持[]訪問,需迭代器)cout << "list元素:";for (auto it = lst.begin(); it != lst.end(); ++it) {cout << *it << " ";}cout << endl; // 輸出:0 3 1 4 1 5 6// 3. 中間插入/刪除auto it = lst.begin();advance(it, 2); // 移動迭代器到第2個元素(值為3的下一個元素1)lst.insert(it, 99); // 在1前插入99cout << "插入后元素:";for (int num : lst) { // 范圍for循環cout << num << " ";}cout << endl; // 輸出:0 3 99 1 4 1 5 6// 4. 刪除指定值的元素lst.remove(1); // 刪除所有值為1的元素cout << "刪除1后元素:";for (int num : lst) {cout << num << " ";}cout << endl; // 輸出:0 3 99 4 5 6return 0;
}
2.3?std::deque
:雙端隊列
特性:分段連續內存,支持兩端高效插入 / 刪除,隨機訪問效率略低于 vector。
適用場景:需要頻繁在頭部和尾部操作的場景(如實現隊列、緩沖區)。
代碼示例:
#include <iostream>
#include <deque>
using namespace std;int main() {deque<int> dq;// 1. 兩端插入dq.push_back(10); // 尾部插入dq.push_front(5); // 頭部插入dq.push_back(20);dq.push_front(1);// 2. 隨機訪問cout << "dq[1] = " << dq[1] << endl; // 輸出5cout << "dq.at(2) = " << dq.at(2) << endl; // 輸出10// 3. 遍歷cout << "deque元素:";for (int num : dq) {cout << num << " ";}cout << endl; // 輸出:1 5 10 20// 4. 兩端刪除dq.pop_front(); // 刪除頭部元素1dq.pop_back(); // 刪除尾部元素20cout << "刪除后元素:";for (int num : dq) {cout << num << " ";}cout << endl; // 輸出:5 10return 0;
}
三、關聯容器(Associative Containers)
關聯容器基于鍵(Key)存儲元素,內部通常用紅黑樹實現,元素自動排序,支持高效查找。
3.1?std::set
:有序唯一集合
特性:元素唯一且按升序排列,插入 / 查找 / 刪除時間復雜度 O (log n)。
適用場景:需要去重并保持有序的集合(如存儲唯一 ID、實現集合運算)。
代碼示例:
#include <iostream>
#include <set>
using namespace std;int main() {// 初始化(自動排序+去重)set<int> s = {5, 2, 8, 2, 5, 9};// 1. 插入元素s.insert(3);// 2. 遍歷(默認升序)cout << "set元素:";for (int num : s) {cout << num << " ";}cout << endl; // 輸出:2 3 5 8 9// 3. 查找元素auto it = s.find(5);if (it != s.end()) {cout << "找到元素:" << *it << endl;} else {cout << "未找到元素" << endl;}// 4. 刪除元素s.erase(8); // 刪除值為8的元素cout << "刪除8后元素:";for (int num : s) {cout << num << " ";}cout << endl; // 輸出:2 3 5 9return 0;
}
3.2?std::map
:有序鍵值對映射
特性:鍵唯一且按升序排列,通過鍵快速訪問值,時間復雜度 O (log n)。
適用場景:需要鍵值對映射的場景(如字典、配置表、索引表)。
代碼示例:
#include <iostream>
#include <map>
#include <string>
using namespace std;int main() {// 初始化鍵值對(鍵為int,值為string)map<int, string> student;// 1. 插入元素(三種方式)student[101] = "Alice"; // 下標法student.insert(pair<int, string>(102, "Bob")); // pair插入student.emplace(103, "Charlie"); // emplace(更高效)// 2. 遍歷鍵值對cout << "學生信息:" << endl;for (auto& pair : student) { // 注意用引用避免拷貝cout << "學號:" << pair.first << ",姓名:" << pair.second << endl;}// 輸出:// 學號:101,姓名:Alice// 學號:102,姓名:Bob// 學號:103,姓名:Charlie// 3. 查找鍵對應的值int id = 102;auto it = student.find(id);if (it != student.end()) {cout << id << "對應的姓名:" << it->second << endl; // 輸出Bob}// 4. 刪除鍵student.erase(101);cout << "刪除101后學號101是否存在:" << (student.count(101) ? "是" : "否") << endl; // 輸出否return 0;
}
3.3?std::multiset
?與?std::multimap
:允許重復鍵
特性:multiset
?允許重復元素,multimap
?允許重復鍵,均有序排列。
適用場景:需要存儲重復元素 / 鍵的場景(如統計頻率、一對多映射)。
代碼示例(multimap
):
#include <iostream>
#include <map>
#include <string>
using namespace std;int main() {// 課程-學生映射(一門課對應多個學生)multimap<string, string> course;// 插入重復鍵course.insert({"Math", "Alice"});course.insert({"Math", "Bob"});course.insert({"Physics", "Charlie"});course.insert({"Math", "David"});// 1. 遍歷所有鍵值對cout << "所有課程學生:" << endl;for (auto& pair : course) {cout << pair.first << ":" << pair.second << endl;}// 2. 查找特定鍵的所有值string key = "Math";cout << "\n" << key << "的學生:" << endl;auto range = course.equal_range(key); // 獲取鍵為Math的范圍for (auto it = range.first; it != range.second; ++it) {cout << it->second << endl; // 輸出Alice、Bob、David}return 0;
}
四、無序關聯容器(Unordered Associative Containers)
C++11 引入,基于哈希表實現,元素無序,平均插入 / 查找 / 刪除時間復雜度 O (1)。
4.1?std::unordered_set
:無序唯一集合
特性:元素唯一、無序,哈希表存儲,查找效率極高(無排序開銷)。
適用場景:只需去重和快速查找,不關心順序的場景(如黑名單、存在性判斷)。
代碼示例:
#include <iostream>
#include <unordered_set>
using namespace std;int main() {unordered_set<string> fruits = {"apple", "banana", "orange"};// 1. 插入元素fruits.insert("grape");// 2. 遍歷(無序)cout << "無序集合元素:";for (auto& fruit : fruits) {cout << fruit << " ";}cout << endl; // 輸出順序不確定// 3. 快速查找string target = "banana";if (fruits.count(target)) { // count()判斷存在性cout << target << " 存在于集合中" << endl;}return 0;
}
4.2?std::unordered_map
:無序鍵值對映射
特性:鍵唯一、無序,哈希表存儲,適合高頻查找場景。
適用場景:需要快速鍵值映射且不關心順序的場景(如緩存、哈希表)。
代碼示例:
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;int main() {// 姓名-年齡映射(無序)unordered_map<string, int> age;age["Alice"] = 20;age["Bob"] = 22;age["Charlie"] = 21;// 1. 遍歷(無序)cout << "姓名-年齡:" << endl;for (auto& pair : age) {cout << pair.first << ":" << pair.second << endl;}// 2. 查找效率對比(哈希表 vs 紅黑樹)// 對于高頻查找,unordered_map性能優于mapcout << "Bob的年齡:" << age["Bob"] << endl;return 0;
}
五、容器適配器(Container Adapters)
基于基礎容器封裝的特殊接口,簡化特定場景使用。
5.1?std::stack
:棧(LIFO)
特性:后進先出,基于 deque 默認實現,支持push
(入棧)、pop
(出棧)、top
(取棧頂)。
適用場景:表達式求值、括號匹配、深度優先搜索(DFS)。
代碼示例:
#include <iostream>
#include <stack>
using namespace std;int main() {stack<int> st;// 入棧st.push(1);st.push(2);st.push(3);// 棧頂元素cout << "棧頂元素:" << st.top() << endl; // 輸出3// 出棧st.pop(); // 刪除棧頂元素3cout << "出棧后棧頂:" << st.top() << endl; // 輸出2// 棧大小cout << "棧大小:" << st.size() << endl; // 輸出2return 0;
}
5.2?std::queue
:隊列(FIFO)
特性:先進先出,基于 deque 默認實現,支持push
(入隊)、pop
(出隊)、front
(隊首)。
適用場景:任務調度、廣度優先搜索(BFS)、消息隊列。
代碼示例:
#include <iostream>
#include <queue>
using namespace std;int main() {queue<string> q;// 入隊q.push("任務1");q.push("任務2");q.push("任務3");// 隊首元素cout << "隊首任務:" << q.front() << endl; // 輸出任務1// 出隊q.pop(); // 移除任務1cout << "出隊后隊首:" << q.front() << endl; // 輸出任務2// 隊列大小cout << "隊列大小:" << q.size() << endl; // 輸出2return 0;
}
5.3?std::priority_queue
:優先隊列
特性:元素按優先級排序(默認最大元素優先),基于 vector 默認實現。
適用場景:定時器、任務調度(高優先級先執行)、最大 / 最小堆場景。
代碼示例:
#include <iostream>
#include <queue>
using namespace std;int main() {// 最大優先隊列(默認)priority_queue<int> maxHeap;maxHeap.push(3);maxHeap.push(1);maxHeap.push(5);cout << "最大堆頂:" << maxHeap.top() << endl; // 輸出5// 最小優先隊列(通過greater<>實現)priority_queue<int, vector<int>, greater<int>> minHeap;minHeap.push(3);minHeap.push(1);minHeap.push(5);cout << "最小堆頂:" << minHeap.top() << endl; // 輸出1return 0;
}
六、容器選型決策指南
容器類型 | 核心特性 | 時間復雜度(插入 / 查找 / 刪除) | 適用場景 |
---|---|---|---|
vector | 連續內存,隨機訪問 | 尾部 O (1),中間 O (n) / O (1) | 隨機訪問、尾部操作多 |
list | 雙向鏈表,任意位置操作高效 | O(1) / O(n) | 頻繁中間插入 / 刪除 |
deque | 雙端操作高效,隨機訪問 | 兩端 O (1) / O (1) | 雙端頻繁操作 |
set /map | 有序,唯一鍵,紅黑樹 | O(log n) / O(log n) | 有序集合、鍵值映射,需排序 |
unordered_set /unordered_map | 無序,哈希表 | 平均 O (1) / 平均 O (1) | 高頻查找,不關心順序 |
stack /queue | 適配器,LIFO/FIFO | O(1) | 棧 / 隊列特定場景 |
priority_queue | 優先級排序 | O(log n) | 高優先級任務調度 |
七、總結
STL 容器為 C++ 開發者提供了開箱即用的數據結構解決方案,掌握各類容器的特性和適用場景是編寫高效代碼的基礎。實際開發中需根據訪問方式、操作頻率、排序需求等因素選型:
- 需隨機訪問選
vector
/deque
; - 需有序且高效查找選
set
/map
; - 需極致查找性能且無序選
unordered_*
; - 需特定數據結構行為選適配器(
stack
/queue
等)。