我是 AlanWu。刚开始学习 C++ 时,我对“我需要存储多个东西”这个问题的回答总是数组。int arr[1000]。每一次都是如此。
后来我发现了 STL 容器,才意识到自己之前太辛苦了。下面是何时该用什么。
vector —— 你的新默认选择
如果你过去会写 int arr[1000],那么现在请改用 vector<int> arr。它可以增长、可以缩小,还知道自己的大小,而且你把它传给函数时不必再单独传长度。
// Old way
int scores[100];
int n = 0;
scores[n++] = 95; // hope n doesn't exceed 99
// New way
vector<int> scores;
scores.push_back(95); // never overflow, never count manually
Enter fullscreen mode Exit fullscreen mode
使用 vector 的场景:你需要一组有序的元素,主要在末尾追加或通过索引访问。
不使用 vector 的场景:你需要频繁在中间插入或删除元素。那是 O(n) 操作——后续所有元素都需要移动。
map —— 当你需要按名称查找时
数组和 vector 使用整数索引。如果你想通过姓名而不是数字来查询学生的分数呢?
map<string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 88;
cout << scores["Alice"]; // 95
Enter fullscreen mode Exit fullscreen mode
map 的底层是一个平衡二叉搜索树。查找复杂度为 O(log n),而不是 O(1)。但对于大多数场景,它已经足够快,而且代码极其简洁。
使用 map 的场景:你有键值对,且键不只是 0、1、2、3……
不使用 map 的场景:你只需要整数索引——那正是 vector 的用武之地。或者当你需要平均 O(1) 的查找时——这时应该用 unordered_map。
unordered_map —— 同样的功能,但通常更快
unordered_map<string, int> scores;
scores["Alice"] = 95;
Enter fullscreen mode Exit fullscreen mode
它看起来和 map 完全一样。区别在于 unordered_map 使用哈希表。平均查找复杂度为 O(1) 而非 O(log n)。但最坏情况下(发生哈希冲突时)会退化为 O(n),键没有顺序,且占用更多内存。
我的原则是:先用 unordered_map。如果需要键有序,再切换到 map。
set —— 当你只关心某物是否存在时
需要记录你已经见过的 ID?不要用 vector 每次都遍历一遍。
set<int> seen;
seen.insert(42);
seen.insert(17);
if (seen.count(42)) { // true — O(log n)
// already seen it
}
Enter fullscreen mode Exit fullscreen mode
set 存储唯一值并保持有序。不允许重复。
如果需要平均 O(1) 且不需要有序:使用 unordered_set。
实际的决策树
- 你是否通过位置(0、1、2…)访问?→ vector。
- 你是否需要通过非数字的键查找?→ unordered_map。
- 这些键是否需要保持有序?→ map。
- 你是否只关心“我是否见过这个”?→ unordered_set。
- 你是否需要这些值有序或不允许重复?→ set。
这覆盖了 90% 的场景。
你大概不需要的容器:deque
我看到初学者因为 deque 听起来很酷而使用它。双端队列,可以在两端插入。
除非你正在写滑动窗口算法或调度器,否则你不需要 deque。vector 配合 push_back 更快也更简单。
总结
下次你想要用普通数组时,先问问自己:vector、map 或 set 能否用一半的代码完成这件事?答案通常是肯定的。
我的 GitHub:https://github.com/Cn-Alanwu
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.