万能头文件
#include <bits/stdc++.h> using namespace std;bits/stdc++.h 包含了绝大多数标准库头文件,在算法竞赛和面试手撕代码时能显著节省书写时间。
注意:这是 GCC 编译器特有的非标准头文件,在 MSVC 或某些严格环境下可能无法使用,但在绝大多数在线笔试平台(牛客、LeetCode C++ 环境通常支持 GCC)中可正常工作。
一、动态数组 vector
声明:
vector<int> v; // 空数组 vector<int> v(10); // 10 个 0 vector<int> v(10, 5); // 10 个 5 vector<vector<int>> matrix(5, vector<int>(5, 0)); // 5x5 二维数组 vector<int> v = {1, 2, 3}; // 列表初始化常用操作:
操作 | 代码 | 复杂度 |
尾部添加 | v.push_back(x) | 均摊 O(1) |
尾部删除 | v.pop_back() | O(1) |
访问元素 | v[i] 或 v.at(i) | O(1) |
首尾迭代器 | v.begin(), v.end() | O(1) |
大小/空判断 | v.size(), v.empty() | O(1) |
指定位置插入 | v.insert(v.begin()+i, x) | O(n) |
指定位置删除 | v.erase(v.begin()+i) | O(n) |
调整大小 | v.resize(n) | O(n) |
排序 | sort(v.begin(), v.end()) | O(n log n) |
二分查找(有序) | binary_search(v.begin(), v.end(), x) | O(log n) |
常用技巧:
// 去重(需先排序) sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); // 二维数组遍历 for (auto& row : matrix) { for (int x : row) cout << x << " "; }二、栈 stack
声明:
stack<int> s;常用操作:
操作 | 代码 |
入栈 | s.push(x) |
出栈 | s.pop()(无返回值) |
取栈顶 | s.top() |
判空 | s.empty() |
大小 | s.size() |
栈适用于括号匹配、逆波兰表达式求值、单调栈等场景。底层默认使用 deque,但是相对来说算是细节,一般不需要关心 。
三、队列 queue
声明:
queue<int> q;常用操作:
操作 | 代码 |
入队 | q.push(x) |
出队 | q.pop()(无返回值) |
取队首 | q.front() |
取队尾 | q.back() |
判空/大小 | q.empty(), q.size() |
BFS 的标配容器。如果需要双端操作,使用 deque:
deque<int> dq; dq.push_back(x); // 尾插 dq.push_front(x); // 头插 O(1) dq.pop_back(); dq.pop_front();四、优先队列 priority_queue
声明:
priority_queue<int> pq; // 大顶堆(默认) priority_queue<int, vector<int>, greater<int>> min_pq; // 小顶堆常用操作:
操作 | 代码 |
插入 | pq.push(x) |
删除堆顶 | pq.pop() |
取堆顶 | pq.top() |
判空/大小 | pq.empty(), pq.size() |
自定义类型:
struct Node { int dist; int id; }; struct cmp { bool operator()(Node& a, Node& b) { return a.dist > b.dist; // 距离小的优先级高(小顶堆) } }; priority_queue<Node, vector<Node>, cmp> pq;适用于 Dijkstra、Top K 问题、任务调度等 。
五、链表 list
声明:
list<int> lst;常用操作:
操作 | 代码 |
头/尾插入 | lst.push_front(x), lst.push_back(x) |
头/尾删除 | lst.pop_front(), lst.pop_back() |
指定位置插入 | lst.insert(it, x) |
删除元素 | lst.erase(it) |
排序 | lst.sort() |
判空/大小 | lst.empty(), lst.size() |
list 是双向链表,不支持随机访问[]。插入删除 O(1)(已知迭代器位置),但查找 O(n) 。
手撕链表通常需要手写节点结构,因为面试官考察的是指针操作:
struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} };六、树(set / map:平衡二叉搜索树)
STL 没有直接提供“树”容器,但 set 和 map 底层是红黑树(平衡 BST),提供 O(log n) 的有序操作。
set(有序集合,去重)
声明:
set<int> s;常用操作:
s.insert(x); // 插入 O(log n) s.erase(x); // 删除 s.find(x); // 查找,返回迭代器 s.count(x); // 存在返回 1 s.lower_bound(x); // >= x 的第一个元素 s.upper_bound(x); // > x 的第一个元素map(有序键值对)
声明:
map<string, int> mp;常用操作:
mp["key"] = 1; // 插入/修改 mp.insert({"key", 1}); mp.erase("key"); mp.find("key"); // 返回迭代器 mp.count("key"); // 判断存在 for (auto& [k, v] : mp) // C++17 结构化绑定遍历 cout << k << ": " << v;手写二叉树节点
struct TreeNode { int val; TreeNode *left, *right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} };七、哈希表 unordered_map / unordered_set
声明:
unordered_map<int, int> hashmap; // 键值对 unordered_set<int> hashset; // 集合常用操作(与 map/set 类似,但无序):
操作 | 代码 | 平均复杂度 |
插入/修改 | mp[key] = val | O(1) |
查找 | mp.find(key) | O(1) |
存在判断 | mp.count(key) | O(1) |
删除 | mp.erase(key) | O(1) |
关键区别:
unordered_map 平均 O(1),但最坏 O(n)(哈希冲突),且无序
map 稳定 O(log n),有序,可用 lower_bound
面试中涉及“查找/计数/去重”且不要求顺序时,优先使用 unordered_map 或 unordered_set 。
八、图(邻接表表示)
C++ STL 没有内置图容器,通常用 vector 模拟邻接表:
// 邻接表:g[u] 存储 u 的所有邻居 vector<vector<int>> g(n + 1); // 添加有向边 u -> v g[u].push_back(v); // 添加无向边 g[u].push_back(v); g[v].push_back(u); // 带权图:pair<邻点, 权重> vector<vector<pair<int, int>>> wg(n + 1); wg[u].push_back({v, w});BFS 遍历模板:
queue<int> q; vector<bool> visited(n + 1, false); q.push(start); visited[start] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (int v : g[u]) { if (!visited[v]) { visited[v] = true; q.push(v); } } }DFS 递归模板:
void dfs(int u, vector<vector<int>>& g, vector<bool>& visited) { visited[u] = true; for (int v : g[u]) { if (!visited[v]) dfs(v, g, visited); } }九、C++17 结构化绑定(强烈推荐)
在遍历 map 或 vector<pair> 时,结构化绑定可以大幅简化代码:
// 以前 for (auto& it : mp) { cout << it.first << " " << it.second; } // C++17 for (auto& [key, value] : mp) { cout << key << " " << value; }配合 auto&& 使用可以避免不必要的拷贝。