STL容器速查表¶
顺序容器¶
vector (动态数组)¶
特性: 动态大小, 随机访问, 尾部插入删除O(1), 中间插入删除O(n)
常用操作:
vector<int> v;
v.push_back(x); // 尾部插入
v.pop_back(); // 尾部删除
v[i] = x; // 随机访问
v.at(i); // 安全访问(带边界检查)
v.insert(it, x); // 指定位置插入
v.erase(it); // 删除指定位置
v.size(); // 大小
v.empty(); // 是否为空
v.clear(); // 清空
v.resize(n); // 重新设置大小
v.reserve(n); // 预留容量
list (双向链表)¶
特性: 双向链表, 任意位置插入删除O(1), 不支持随机访问
常用操作:
list<int> l;
l.push_back(x); // 尾部插入
l.push_front(x); // 头部插入
l.pop_back(); // 尾部删除
l.pop_front(); // 头部删除
l.insert(it, x); // 指定位置插入
l.erase(it); // 删除指定位置
l.remove(x); // 删除所有值为x的元素
l.sort(); // 排序
l.reverse(); // 反转
l.unique(); // 去重(需先排序)
deque (双端队列)¶
特性: 双端队列, 头尾插入删除O(1), 随机访问O(1)
常用操作:
deque<int> dq;
dq.push_back(x); // 尾部插入
dq.push_front(x); // 头部插入
dq.pop_back(); // 尾部删除
dq.pop_front(); // 头部删除
dq[i] = x; // 随机访问
dq.at(i); // 安全访问
关联容器¶
set (有序集合)¶
特性: 红黑树实现, 自动排序, 元素唯一, 查找O(logn)
常用操作:
set<int> s;
s.insert(x); // 插入
s.erase(x); // 删除值为x的元素
s.erase(it); // 删除迭代器位置
s.find(x); // 查找, 返回迭代器
s.count(x); // 统计个数(0或1)
s.lower_bound(x); // 第一个>=x的位置
s.upper_bound(x); // 第一个>x的位置
s.begin(), s.end(); // 迭代器
map (有序映射)¶
特性: 红黑树实现, key-value对, key唯一且自动排序, 查找O(logn)
常用操作:
map<string, int> m;
m[key] = value; // 插入/修改
m.insert({key, value}); // 插入
m.erase(key); // 删除
m.find(key); // 查找
m.count(key); // 统计个数(0或1)
m.lower_bound(key); // 第一个>=key的位置
m.upper_bound(key); // 第一个>key的位置
unordered_set (无序集合)¶
特性: 哈希表实现, 无序, 元素唯一, 平均查找O(1)
常用操作:
unordered_set<int> us;
us.insert(x); // 插入
us.erase(x); // 删除
us.find(x); // 查找
us.count(x); // 统计个数(0或1)
us.bucket_count(); // 桶数量
us.load_factor(); // 负载因子
unordered_map (无序映射)¶
特性: 哈希表实现, key-value对, key唯一, 无序, 平均查找O(1)
常用操作:
unordered_map<string, int> um;
um[key] = value; // 插入/修改
um.insert({key, value}); // 插入
um.erase(key); // 删除
um.find(key); // 查找
um.count(key); // 统计个数(0或1)
容器适配器¶
stack (栈)¶
特性: LIFO(后进先出), 基于deque实现
常用操作:
stack<int> st;
st.push(x); // 入栈
st.pop(); // 出栈(无返回值)
st.top(); // 栈顶元素
st.empty(); // 是否为空
st.size(); // 大小
queue (队列)¶
特性: FIFO(先进先出), 基于deque实现
常用操作:
queue<int> q;
q.push(x); // 入队
q.pop(); // 出队(无返回值)
q.front(); // 队首元素
q.back(); // 队尾元素
q.empty(); // 是否为空
q.size(); // 大小
priority_queue (优先队列)¶
特性: 大顶堆(默认), 基于vector实现, 自动维护最大值在堆顶
常用操作:
priority_queue<int> pq; // 大顶堆
priority_queue<int, vector<int>, greater<int>> pq2; // 小顶堆
pq.push(x); // 插入
pq.pop(); // 删除堆顶(无返回值)
pq.top(); // 堆顶元素
pq.empty(); // 是否为空
pq.size(); // 大小
Lambda表达式¶
语法: [capture](parameters) -> return_type { body }
捕获方式:
- []: 不捕获任何变量
- [=]: 按值捕获所有变量
- [&]: 按引用捕获所有变量
- [var]: 按值捕获var
- [&var]: 按引用捕获var
- [=, &var]: 按值捕获所有变量, 按引用捕获var
常用示例:
// 基本语法
auto lambda = [](int x) { return x * 2; };
// 捕获外部变量
int factor = 3;
auto multiply = [factor](int x) { return x * factor; };
// STL算法中使用
vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
// 自定义比较器
auto cmp = [](const pair<int,int>& a, const pair<int,int>& b) {
return a.second < b.second;
};
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(cmp)> pq(cmp);
容器选择指南¶
| 需求 | 推荐容器 |
|---|---|
| 随机访问 + 尾部操作 | vector |
| 频繁头尾操作 | deque |
| 频繁中间插入删除 | list |
| 需要排序的唯一元素 | set |
| key-value映射且需排序 | map |
| 快速查找唯一元素 | unordered_set |
| 快速key-value查找 | unordered_map |
| LIFO操作 | stack |
| FIFO操作 | queue |
| 需要优先级 | priority_queue |
迭代器与for循环遍历¶
迭代器类型¶
迭代器分类:
- 输入迭代器: 只读, 单向
- 输出迭代器: 只写, 单向
- 前向迭代器: 读写, 单向
- 双向迭代器: 读写, 双向 (list, set, map)
- 随机访问迭代器: 读写, 随机访问 (vector, deque)
常用迭代器操作:
// 获取迭代器
auto it = container.begin(); // 指向第一个元素
auto it = container.end(); // 指向最后一个元素的下一位
auto it = container.rbegin(); // 反向迭代器, 指向最后一个元素
auto it = container.rend(); // 反向迭代器, 指向第一个元素的前一位
// 迭代器操作
++it; // 前进一位
--it; // 后退一位 (双向/随机访问迭代器)
it += n; // 前进n位 (随机访问迭代器)
it -= n; // 后退n位 (随机访问迭代器)
*it; // 解引用, 获取值
it->member; // 访问成员
for循环遍历方式¶
1. 传统for循环 (适用于vector, deque等支持随机访问的容器)¶
vector<int> v = {1, 2, 3, 4, 5};
// 索引遍历
for (int i = 0; i < v.size(); ++i) {
cout << v[i] << " ";
}
// 安全的索引遍历
for (size_t i = 0; i < v.size(); ++i) {
cout << v[i] << " ";
}
2. 迭代器for循环 (适用于所有容器)¶
// vector示例
vector<int> v = {1, 2, 3, 4, 5};
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it << " ";
}
// set示例
set<int> s = {1, 2, 3, 4, 5};
for (auto it = s.begin(); it != s.end(); ++it) {
cout << *it << " ";
}
// map示例
map<string, int> m = {{"a", 1}, {"b", 2}};
for (auto it = m.begin(); it != m.end(); ++it) {
cout << it->first << ": " << it->second << endl;
}
3. 范围for循环 (C++11) (适用于所有容器)¶
// 基本用法
vector<int> v = {1, 2, 3, 4, 5};
for (int x : v) { // 按值传递
cout << x << " ";
}
for (const int& x : v) { // 按const引用传递 (推荐读取)
cout << x << " ";
}
for (int& x : v) { // 按引用传递 (用于修改)
x *= 2;
}
for (auto x : v) { // 自动类型推导
cout << x << " ";
}
for (const auto& x : v) { // 自动类型推导 + const引用 (最常用)
cout << x << " ";
}
// map的范围for循环
map<string, int> m = {{"a", 1}, {"b", 2}};
for (const auto& pair : m) {
cout << pair.first << ": " << pair.second << endl;
}
// C++17结构化绑定
for (const auto& [key, value] : m) {
cout << key << ": " << value << endl;
}
4. 反向遍历¶
vector<int> v = {1, 2, 3, 4, 5};
// 反向迭代器
for (auto it = v.rbegin(); it != v.rend(); ++it) {
cout << *it << " ";
}
// 索引反向遍历
for (int i = v.size() - 1; i >= 0; --i) {
cout << v[i] << " ";
}
// 更安全的索引反向遍历
for (size_t i = v.size(); i > 0; --i) {
cout << v[i-1] << " ";
}
不同容器的遍历示例¶
vector遍历¶
vector<int> v = {1, 2, 3, 4, 5};
// 方式1: 索引
for (size_t i = 0; i < v.size(); ++i) {
cout << v[i] << " ";
}
// 方式2: 迭代器
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it << " ";
}
// 方式3: 范围for (推荐)
for (const auto& x : v) {
cout << x << " ";
}
set遍历¶
set<int> s = {5, 2, 8, 1, 9};
// 迭代器遍历 (自动排序)
for (auto it = s.begin(); it != s.end(); ++it) {
cout << *it << " "; // 输出: 1 2 5 8 9
}
// 范围for (推荐)
for (const auto& x : s) {
cout << x << " ";
}
map遍历¶
map<string, int> m = {{"apple", 5}, {"banana", 3}, {"orange", 7}};
// 迭代器遍历
for (auto it = m.begin(); it != m.end(); ++it) {
cout << it->first << ": " << it->second << endl;
}
// 范围for
for (const auto& pair : m) {
cout << pair.first << ": " << pair.second << endl;
}
// C++17结构化绑定 (推荐)
for (const auto& [key, value] : m) {
cout << key << ": " << value << endl;
}
list遍历¶
list<int> l = {1, 2, 3, 4, 5};
// 迭代器遍历
for (auto it = l.begin(); it != l.end(); ++it) {
cout << *it << " ";
}
// 范围for (推荐)
for (const auto& x : l) {
cout << x << " ";
}
遍历时的修改操作¶
安全删除元素¶
vector<int> v = {1, 2, 3, 4, 5};
// 删除所有偶数 - 正确方式
for (auto it = v.begin(); it != v.end();) {
if (*it % 2 == 0) {
it = v.erase(it); // erase返回下一个有效迭代器
} else {
++it;
}
}
// set/map的删除
set<int> s = {1, 2, 3, 4, 5};
for (auto it = s.begin(); it != s.end();) {
if (*it % 2 == 0) {
it = s.erase(it);
} else {
++it;
}
}
修改元素值¶
vector<int> v = {1, 2, 3, 4, 5};
// 所有元素乘以2
for (auto& x : v) { // 注意使用引用
x *= 2;
}
// 使用迭代器修改
for (auto it = v.begin(); it != v.end(); ++it) {
*it *= 2;
}
性能建议¶
- 优先使用范围for循环: 代码简洁, 性能好
- 读取时使用const引用:
for (const auto& x : container) - 修改时使用引用:
for (auto& x : container) - vector用索引也很高效: 特别是需要索引值时
- 避免在遍历时修改容器大小: 可能导致迭代器失效
常见错误¶
// 错误: 迭代器失效
vector<int> v = {1, 2, 3, 4, 5};
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it == 3) {
v.erase(it); // 错误! it失效了
// ++it; // 错误! 对失效迭代器操作
}
}
// 错误: 拷贝开销大
vector<string> v = {"long string 1", "long string 2"};
for (auto x : v) { // 错误! 发生拷贝
cout << x << endl;
}
// 正确
for (const auto& x : v) { // 正确! 使用引用
cout << x << endl;
}