🚀 C++ 集合(set、unordered_set、map、unordered_map)全面解析
C++ STL 提供了多种高效存储和查找数据的容器,本文深入解析集合(Set)和映射(Map)及其变体的特性、用法和适用场景。
📌 1. set 和 unordered_set(集合)
1.1 set(有序集合)
-
特点:
- 自动排序(默认升序)。
- 元素唯一,不允许重复。
- 底层数据结构:红黑树。
- 查找、插入、删除的时间复杂度:O(log n)。
- 元素不可修改(修改会破坏排序)。
-
头文件:
#include <set> -
示例代码:
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(5);
s.insert(3);
s.insert(8);
s.insert(3); // 重复元素插入失败
// 遍历输出:3 5 8(自动排序)
for (int x : s) cout << x << " ";
// 查找元素
if (s.find(5) != s.end()) {
cout << "\n5 存在" << endl;
}
s.erase(5); // 删除元素
return 0;
}
🌟 适用场景:需有序且元素唯一的场景(如去重+排序)。
1.2 unordered_set(无序集合)
-
特点:
- 元素唯一,无序存储。
- 底层数据结构:哈希表。
- 查找、插入、删除的平均时间复杂度:O(1),最坏情况 O(n)。
- 需自定义哈希函数(若键为自定义类型)。
-
头文件:
#include <unordered_set> -
示例代码:
#include <unordered_set>
using namespace std;
int main() {
unordered_set<int> us;
us.insert(5);
us.insert(3);
us.insert(8);
us.insert(3); // 插入失败
// 遍历输出顺序不定(如5 3 8)
for (int x : us) cout << x << " ";
return 0;
}
🌟 适用场景:需快速查找且不关心顺序。
📌 2. map 和 unordered_map(键值对映射)
2.1 map(有序映射)
-
特点:
- 按键自动排序(默认升序)。
- 键唯一,值可重复。
- 底层数据结构:红黑树。
- 操作时间复杂度:O(log n)。
- 键不可修改,值可修改。
-
头文件:
#include <map> -
示例代码:
#include <map>
using namespace std;
int main() {
map<string, int> m;
m["apple"] = 3; // 插入或修改键为"apple"的值
m.insert({"banana", 2}); // 插入键值对,若键存在则失败
// 遍历按键升序输出
for (auto& p : m) {
cout << p.first << ": " << p.second << endl;
}
return 0;
}
🌟 适用场景:需有序键值对的存储(如字典排序)。
2.2 unordered_map(无序映射)
-
特点:
- 无序存储键值对。
- 底层数据结构:哈希表。
- 平均时间复杂度:O(1),最坏情况 O(n)。
- 需为自定义键类型提供哈希函数和
==运算符。
-
头文件:
#include <unordered_map> -
示例代码:
#include <unordered_map>
using namespace std;
int main() {
unordered_map<string, int> um;
um["apple"] = 3;
um["banana"] = 2;
// 遍历输出顺序不定
for (auto& p : um) {
cout << p.first << ": " << p.second << endl;
}
return 0;
}
🌟 适用场景:需快速查找键值对且不关心顺序。
📌 3. 允许多个相同元素的集合(Multi 版本)
3.1 multiset(有序多重集合)
-
特点:
- 允许重复元素,自动排序。
- 底层结构:红黑树。
- 时间复杂度:O(log n)。
-
头文件:
#include <set> -
示例代码:
multiset<int> ms;
ms.insert(3);
ms.insert(3); // 允许重复
// 输出:3 3 5 8(有序)
3.2 multimap(有序多重映射)
-
特点:
- 允许重复键,按键排序。
- 不支持
operator[](因键不唯一)。
-
头文件:
#include <map> -
示例代码:
multimap<string, int> mm;
mm.insert({"apple", 3});
mm.insert({"apple", 4}); // 允许重复键
3.3 unordered_multiset 和 unordered_multimap
- 特点:
- 无序存储,允许重复元素/键。
- 底层结构:哈希表。
- 平均时间复杂度:O(1)。
📊 总结对比表
| 容器 | 有序性 | 唯一性 | 底层结构 | 时间复杂度 | 适用场景 |
|---|---|---|---|---|---|
set | ✅ 升序 | 键唯一 | 红黑树 | O(log n) | 有序唯一集合 |
unordered_set | ❌ 无序 | 键唯一 | 哈希表 | O(1) 平均, O(n) 最坏 | 快速查找无需排序 |
map | ✅ 升序 | 键唯一 | 红黑树 | O(log n) | 有序键值对 |
unordered_map | ❌ 无序 | 键唯一 | 哈希表 | O(1) 平均, O(n) 最坏 | 快速键值查找 |
multiset | ✅ 升序 | 允许重复 | 红黑树 | O(log n) | 有序可重复集合 |
multimap | ✅ 升序 | 允许重复键 | 红黑树 | O(log n) | 有序键可重复映射 |
unordered_multiset | ❌ 无序 | 允许重复 | 哈希表 | O(1) 平均, O(n) 最坏 | 快速查找可重复元素 |
unordered_multimap | ❌ 无序 | 允许重复键 | 哈希表 | O(1) 平均, O(n) 最坏 | 快速查找可重复键 |
🎯 选择指南
- 快速查找 + 无需排序 →
unordered_map/unordered_set - 有序存储 →
map/set - 允许重复元素 →
multiset/multimap - 自定义键类型 → 提供哈希函数和
==运算符(仅 unordered 容器需要)
⚠️ 注意事项
- 哈希冲突:
unordered_*容器在哈希冲突严重时性能下降,需合理设计哈希函数。 - 修改元素:
set和map的键不可修改,值可修改(map的值通过迭代器修改)。 - 插入方式:
map的operator[]会插入默认值,而insert不会覆盖已有键。 - 自定义键:使用
unordered_map自定义键时,需特化std::hash并重载operator==。
通过理解各容器的特性,能更高效地选择适合的数据结构解决问题。 🚀


全面解析&spm=1001.2101.3001.5002&articleId=146158486&d=1&t=3&u=b7d7dfaae7b34281a90edc1fad91f94e)
1971

被折叠的 条评论
为什么被折叠?



