std::unordered_set
和 std::unordered_map
的 核心设计思想相似(均基于哈希表实现,提供 O(1) 平均时间复杂度的查找),但它们的 API 并不完全相同,主要区别源于二者用途不同:
• unordered_map
存储键值对(key-value
),需通过键访问值。
• unordered_set
仅存储键(key
),用于快速判断元素是否存在。
1. 相同点
以下 API 在两者中功能一致:
操作 | 功能说明 | 示例(unordered_map / unordered_set ) |
---|---|---|
insert() | 插入元素 | map.insert({key, value}) / set.insert(key) |
emplace() | 直接构造元素(避免拷贝) | map.emplace(key, value) / set.emplace(key) |
erase() | 删除指定元素 | map.erase(key) / set.erase(key) |
find() | 查找元素,返回迭代器 | auto it = map.find(key) / auto it = set.find(key) |
count() | 返回元素是否存在(0 或 1) | if (map.count(key)) / if (set.count(key)) |
size() | 返回元素数量 | map.size() / set.size() |
empty() | 判断容器是否为空 | map.empty() / set.empty() |
clear() | 清空所有元素 | map.clear() / set.clear() |
begin() , end() | 返回迭代器 | 用于遍历容器 |
2. 不同点
(1)元素访问
• unordered_map
提供 operator[]
和 at()
直接访问值:
unordered_map<string, int> map = {{"Alice", 25}};
cout << map["Alice"]; // 输出 25(若 key 不存在会自动插入默认值!)
cout << map.at("Alice"); // 输出 25(若 key 不存在抛出异常)
unordered_set
没有这些接口,因为它不存储值。
(2)迭代器解引用
• unordered_map
的迭代器指向 pair<const Key, T>
,需用 it->first
和 it->second
访问键和值:
for (auto it = map.begin(); it != map.end(); ++it) {
cout << it->first << ": " << it->second; // 输出键值对
}
• unordered_set
的迭代器直接指向 Key
:
unordered_set<int> set = {1, 2, 3};
for (auto it = set.begin(); it != set.end(); ++it) {
cout << *it; // 输出元素值
}
(3)初始化与插入
• unordered_map
插入键值对需用 {key, value}
:
map.insert({"Bob", 30});
• unordered_set
只需插入键:
set.insert(42);
3. 何时选择?
• 用 unordered_map
:
需要建立 键到值的映射(如统计词频、缓存键值对)。
unordered_map<string, int> word_count;
word_count["hello"]++; // 统计单词出现次数
• 用 unordered_set
:
只需 快速判断元素是否存在(如去重、检查重复)。
unordered_set<int> seen;
if (seen.count(num)) return true; // 检查重复数字
4. 性能注意事项
• 两者均为哈希实现,但 unordered_map
存储更多数据(需存值),内存占用略高。
• 均需注意哈希冲突,复杂键类型需自定义哈希函数(如对自定义类或 pair
哈希)。
总结
• 相同点:插入、删除、查找等基础操作接口一致。
• 不同点:
• unordered_map
提供键值对访问([]
、at
),迭代器解引用为 pair
。
• unordered_set
仅存储键,更轻量级。
根据场景选择:需要关联值时用 map
,只需存在性检查时用 set
。