全面掌握C++标准模板库中的容器类型,了解其特点、适用场景和最佳实践
STL容器是用于存储和管理数据集合的模板类,提供了数据组织、访问和操作的统一接口。C++标准库提供了多种容器类型,每种针对特定使用场景进行了优化。
vector, list, deque, array
set, multiset, map, multimap
unordered_set, unordered_multiset, unordered_map, unordered_multimap
stack, queue, priority_queue
#include <iostream> #include <vector> #include <set> #include <unordered_map> int main() { // 序列容器 - vector std::vector<int> vec = {1, 2, 3}; vec.push_back(4); std::cout << "Vector: "; for (int n : vec) std::cout << n << " "; // 关联容器 - set std::set<int> s = {3, 1, 4, 1, 5}; std::cout << "\nSet: "; for (int n : s) std::cout << n << " "; // 无序容器 - unordered_map std::unordered_map<std::string, int> ages; ages["Alice"] = 30; ages["Bob"] = 25; std::cout << "\nAlice's age: " << ages["Alice"]; return 0; }
序列容器按线性顺序存储元素,保留了元素的插入顺序。
动态数组,在内存中连续存储元素。支持快速随机访问,尾部插入/删除高效,但中间插入/删除较慢。
#include <iostream> #include <vector> #include <algorithm> int main() { // 创建vector std::vector<int> nums = {3, 1, 4, 1, 5, 9}; // 添加元素 nums.push_back(2); nums.insert(nums.begin() + 2, 7); // 在索引2处插入 // 排序 std::sort(nums.begin(), nums.end()); // 遍历 std::cout << "Vector: "; for (int n : nums) std::cout << n << " "; // 容量操作 std::cout << "\nSize: " << nums.size(); std::cout << "\nCapacity: " << nums.capacity(); // 删除元素 nums.pop_back(); nums.erase(nums.begin() + 3); return 0; }
双向链表实现。在任何位置插入/删除高效,但不支持随机访问。内存占用较高(每个元素需要额外指针空间)。
#include <iostream> #include <list> int main() { std::list<int> lst = {1, 2, 3}; // 添加元素 lst.push_front(0); // 头部插入 lst.push_back(4); // 尾部插入 // 中间插入 auto it = lst.begin(); std::advance(it, 2); lst.insert(it, 10); // 删除元素 lst.pop_front(); lst.remove(3); // 删除所有值为3的元素 // 遍历 std::cout << "List: "; for (int n : lst) std::cout << n << " "; // 排序 lst.sort(); // 合并 std::list<int> lst2 = {5, 6, 7}; lst.merge(lst2); return 0; }
双端队列,支持在头部和尾部高效插入/删除。由多个固定大小的数组块组成,不是完全连续存储。
#include <iostream> #include <deque> int main() { std::deque<int> dq = {2, 3, 4}; // 双端操作 dq.push_front(1); dq.push_back(5); // 访问元素 std::cout << "Front: " << dq.front(); std::cout << "\nBack: " << dq.back(); std::cout << "\nElement at index 2: " << dq[2]; // 中间插入 dq.insert(dq.begin() + 2, 10); // 删除 dq.pop_front(); dq.pop_back(); return 0; }
关联容器基于键自动排序元素,通常使用红黑树实现。
存储唯一键的有序集合。自动排序,不允许重复元素。
#include <iostream> #include <set> int main() { std::set<int> s; // 插入元素 s.insert(3); s.insert(1); s.insert(4); s.insert(1); // 重复元素,不会被插入 // 遍历(自动排序) std::cout << "Set: "; for (int n : s) std::cout << n << " "; // 1 3 4 // 查找 auto it = s.find(3); if (it != s.end()) { std::cout << "\nFound 3"; } // 删除 s.erase(3); return 0; }
存储键值对的有序映射。键唯一,自动按键排序。
#include <iostream> #include <map> #include <string> int main() { std::map<std::string, int> ages; // 插入元素 ages["Alice"] = 30; ages["Bob"] = 25; ages["Charlie"] = 35; // 插入方式2 ages.insert(std::make_pair("David", 28)); // 遍历(按键排序) std::cout << "Ages:\n"; for (const auto& pair : ages) { std::cout << pair.first << ": " << pair.second << "\n"; } // 查找 auto it = ages.find("Bob"); if (it != ages.end()) { std::cout << "Bob's age: " << it->second; } // 删除 ages.erase("Alice"); return 0; }
无序容器使用哈希表实现,提供平均常数时间复杂度的操作。
基于哈希表的集合实现,元素无序存储,不允许重复。
#include <iostream> #include <unordered_set> #include <string> int main() { std::unordered_set<std::string> us; // 插入元素 us.insert("apple"); us.insert("banana"); us.insert("orange"); us.insert("apple"); // 重复,不会被插入 // 遍历(无序) std::cout << "Fruits: "; for (const auto& fruit : us) { std::cout << fruit << " "; } // 查找 if (us.find("banana") != us.end()) { std::cout << "\nFound banana"; } // 桶接口 std::cout << "\nBucket count: " << us.bucket_count(); std::cout << "\nLoad factor: " << us.load_factor(); return 0; }
基于哈希表的键值对映射,元素无序存储,键唯一。
#include <iostream> #include <unordered_map> #include <string> int main() { std::unordered_map<std::string, int> wordCount; // 插入元素 wordCount["apple"] = 5; wordCount["banana"] = 3; wordCount["orange"] = 2; // 插入方式2 wordCount.insert({"grape", 4}); // 更新值 wordCount["apple"]++; // 遍历 std::cout << "Word counts:\n"; for (const auto& pair : wordCount) { std::cout << pair.first << ": " << pair.second << "\n"; } // 查找 if (wordCount.find("banana") != wordCount.end()) { std::cout << "Banana count: " << wordCount["banana"]; } // 桶操作 std::cout << "\nBucket for 'apple': " << wordCount.bucket("apple"); return 0; }
容器适配器提供特定数据结构的接口,基于其他容器实现。
后进先出(LIFO)数据结构,默认基于deque实现。
#include <iostream> #include <stack> int main() { std::stack<int> stk; // 压入元素 stk.push(10); stk.push(20); stk.push(30); std::cout << "Stack size: " << stk.size() << "\n"; std::cout << "Top element: " << stk.top() << "\n"; // 弹出元素 stk.pop(); std::cout << "After pop, top element: " << stk.top() << "\n"; // 检查是否为空 while (!stk.empty()) { std::cout << "Popping: " << stk.top() << "\n"; stk.pop(); } return 0; }
先进先出(FIFO)数据结构,默认基于deque实现。
#include <iostream> #include <queue> int main() { std::queue<std::string> q; // 入队 q.push("Alice"); q.push("Bob"); q.push("Charlie"); std::cout << "Queue size: " << q.size() << "\n"; std::cout << "Front: " << q.front() << "\n"; std::cout << "Back: " << q.back() << "\n"; // 出队 q.pop(); std::cout << "After pop, front: " << q.front() << "\n"; // 遍历队列 std::cout << "Queue elements: "; while (!q.empty()) { std::cout << q.front() << " "; q.pop(); } return 0; }
优先级队列,元素按优先级排序,默认基于vector实现(大顶堆)。
#include <iostream> #include <queue> #include <vector> #include <functional> // 用于greater int main() { // 最大堆(默认) std::priority_queue<int> maxHeap; maxHeap.push(30); maxHeap.push(10); maxHeap.push(50); maxHeap.push(20); std::cout << "Max Heap: "; while (!maxHeap.empty()) { std::cout << maxHeap.top() << " "; maxHeap.pop(); } // 最小堆 std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; minHeap.push(30); minHeap.push(10); minHeap.push(50); minHeap.push(20); std::cout << "\nMin Heap: "; while (!minHeap.empty()) { std::cout << minHeap.top() << " "; minHeap.pop(); } // 自定义优先级 auto cmp = [](int left, int right) { return (left % 10) > (right % 10); // 按个位数从大到小 }; std::priority_queue<int, std::vector<int>, decltype(cmp)> customHeap(cmp); customHeap.push(25); customHeap.push(17); customHeap.push(36); customHeap.push(42); std::cout << "\nCustom Heap: "; while (!customHeap.empty()) { std::cout << customHeap.top() << " "; customHeap.pop(); } return 0; }
不同容器在不同场景下有各自的优势,选择合适的容器可以显著提高程序性能。
容器 | 内部结构 | 随机访问 | 插入/删除效率 | 内存占用 | 元素顺序 | 重复元素 | 最佳使用场景 |
---|---|---|---|---|---|---|---|
vector | 动态数组 | O(1) | 尾部: O(1) 中间: O(n) |
低 | 插入顺序 | 允许 | 随机访问频繁,尾部操作多 |
list | 双向链表 | O(n) | 任意位置 O(1) | 高 | 插入顺序 | 允许 | 频繁在任意位置插入/删除 |
deque | 分块数组 | O(1) | 头尾: O(1) 中间: O(n) |
中 | 插入顺序 | 允许 | 双端队列操作 |
set | 红黑树 | 不支持 | O(log n) | 中 | 排序顺序 | 不允许 | 有序唯一元素集合 |
map | 红黑树 | 不支持 | O(log n) | 中 | 按键排序 | 键唯一 | 键值对映射,需有序 |
unordered_set | 哈希表 | 不支持 | 平均: O(1) 最差: O(n) |
中 | 无序 | 不允许 | 快速查找,不关心顺序 |
unordered_map | 哈希表 | 不支持 | 平均: O(1) 最差: O(n) |
中 | 无序 | 键唯一 | 键值对快速查找 |
stack | 适配器(deque) | 不支持 | 顶部 O(1) | 中 | LIFO | 允许 | 后进先出场景 |
queue | 适配器(deque) | 不支持 | 尾部入队 O(1) 头部出队 O(1) |
中 | FIFO | 允许 | 先进先出场景 |
priority_queue | 适配器(vector) | 不支持 | 插入: O(log n) 删除: O(log n) |
低 | 优先级顺序 | 允许 | 优先级调度,堆操作 |
操作 | vector | list | deque | set/map | unordered_set/map |
---|---|---|---|---|---|
随机访问 | O(1) | O(n) | O(1) | O(n) | O(n) |
头部插入 | O(n) | O(1) | O(1) | O(log n) | 平均 O(1) |
尾部插入 | 平均 O(1) | O(1) | O(1) | O(log n) | 平均 O(1) |
中间插入 | O(n) | O(1) | O(n) | O(log n) | 平均 O(1) |
查找元素 | O(n) | O(n) | O(n) | O(log n) | 平均 O(1) |
删除元素 | O(n) | O(1) | O(n) | O(log n) | 平均 O(1) |