unordered_set插入时自动去重,因其基于哈希表实现,插入前先计算hash值并用operator==比较判等,相等则跳过;自定义类型需提供hash特化和operator==,内置类型默认支持。

unordered_set 插入时自动去重的原理
unordered_set 是 C++ 标准库中基于哈希表实现的无序集合,它在插入元素时会自动检查是否已存在相同值——如果 hash 值相同且 operator== 判定相等,就跳过插入。这不是“额外去重步骤”,而是其底层行为本身。
注意:自定义类型需提供哈希函数和相等比较,否则编译失败。内置类型(如 int、string)已默认支持。
- 重复调用
insert()同一值,返回值的second字段为false,表示未插入成功 - 不保证元素顺序,遍历时顺序不可预测
- 平均时间复杂度为 O(1),但最坏情况(大量哈希冲突)退化为 O(n)
常见去重场景下的写法对比
比如从 vector 中提取唯一整数:
vector<int> nums = {1, 2, 2, 3, 3, 4};
unordered_set<int> unique_nums(nums.begin(), nums.end()); // 构造时直接去重
或逐个插入并判断:
立即学习“C++免费学习笔记(深入)”;
unordered_set<int> s;
for (int x : nums) {
if (s.insert(x).second) {
// 插入成功,x 是新元素
}
}
- 构造初始化更简洁,适合一次性去重;逐个
insert()适合需要在插入时做逻辑分支的场景 - 不要用
find() + insert()组合,效率更低(查一次、再插一次),insert()自带查找 - 若需保留原始顺序,
unordered_set不适用,应配合vector+unordered_set辅助判断
自定义类型使用 unordered_set 的必要条件
例如对 struct Point { int x, y; }; 使用 unordered_set<point></point>,必须显式提供:
- 特化
std::hash<point></point>,重载operator() - 提供
operator==(成员函数或非成员函数均可)
否则编译报错:error: call to implicitly-deleted default constructor of 'std::hash<point>'</point>
简单示例:
struct Point {
int x, y;
bool operator==(const Point& o) const { return x == o.x && y == o.y; }
};
namespace std {
template<> struct hash<Point> {
size_t operator()(const Point& p) const {
return hash<int>{}(p.x) ^ (hash<int>{}(p.y) << 1);
}
};
}
注意:异或(^)不是最佳哈希组合方式,易导致碰撞;生产环境建议用 boost::hash_combine 或更健壮的混入位移。
性能与内存使用的实际影响
unordered_set 默认负载因子上限是 1.0,当元素数 / 桶数 > 1.0 时自动 rehash,触发内存重新分配和所有元素重散列——这会导致短时停顿,且内存占用通常是实际数据的 2–3 倍。
- 若已知最终大小,构造时用
unordered_set<t>(n)</t>预留桶数,避免多次 rehash - 频繁增删场景下,
unordered_set比set更快;但若需遍历有序结果,别指望它排序,得转vector后sort() - 小数据量(如 vector +
unique可能更快,因无哈希开销和内存碎片
哈希表的“快”是有前提的:分布均匀、冲突少、对象拷贝/移动廉价。一旦自定义类型的哈希函数写歪了,或者 operator== 逻辑有误,去重就会失效或崩溃。










