C++STL标准模板库详解
一、引言
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
等)。