1. 删除元素的核心方法
在 C++ 中,std::unordered_set
提供了以下删除元素的方法:
-
通过迭代器删除
语法:iterator erase(const_iterator pos)
作用:删除指定位置的元素,返回被删元素的下一个有效迭代器。
时间复杂度:平均 O ( 1 ) O(1) O(1),最坏 O ( n ) O(n) O(n)(哈希冲突严重时)。 -
通过键值删除
语法:size_type erase(const Key& key)
作用:删除与键值匹配的元素,返回实际删除的数量(0 或 1)。
时间复杂度:平均 O ( 1 ) O(1) O(1)。 -
范围删除
语法:iterator erase(const_iterator first, const_iterator last)
作用:删除迭代器区间 [ f i r s t , l a s t ) [first, last) [first,last) 内的元素,返回last
的下一个迭代器。
2. std::unordered_set 删除元素的底层行为分析
-
哈希表定位
删除元素时,首先通过哈希函数计算键值的哈希值,定位到对应的桶。例如,删除元素
x
的哈希值满足:
(其中 n
是当前桶的数量)
-
冲突处理
若桶内因哈希冲突存在链表或类似结构(开链法),需遍历该结构找到目标元素。例如,删除链表中的节点时,直接调整指针完成移除操作,时间复杂度为 O(k)(
k
为桶内元素数量)。 -
内存与结构变化
-
直接移除元素:底层哈希表不会保留「已删除」标记,而是直接释放内存。
-
桶数量调整:删除操作不会自动触发缩容(即减少桶数量),需手动调用
rehash()
或shrink_to_fit()
来优化内存。
-
3. 关键注意事项
- 迭代器失效:删除元素可能导致部分迭代器失效(尤其是被删元素的迭代器),但其他迭代器仍有效。
- 安全删除模式:在循环中删除元素时,需使用
it = s.erase(it)
更新迭代器,避免直接递增导致未定义行为。 - 性能特性:平均时间复杂度为 O ( 1 ) O(1) O(1),但若哈希表负载因子过高,可能触发重哈希,导致性能下降。
4. 代码示例
#include <unordered_set>
#include <iostream>
int main() {
std::unordered_set<int> s = {1, 2, 3, 4, 5};
// 通过键值删除
s.erase(3); // 删除元素3
// 通过迭代器删除
auto it = s.find(4);
if (it != s.end()) {
s.erase(it); // 删除元素4
}
// 遍历删除偶数
for (auto it = s.begin(); it != s.end();) {
if (*it % 2 == 0) {
it = s.erase(it); // 安全删除并更新迭代器
} else {
++it;
}
}
// 输出剩余元素
for (int x : s) {
std::cout << x << " "; // 输出: 1 5
}
return 0;
}