本文主要是介绍C++中unordered_set哈希集合的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder...
一、概述
std::unordered_set 是 C++ 标准库(C++11 引入)中的无序容器,用于存储唯一的元素(无重复值),底层基于哈希表(哈希桶) 实现。与 std::set(基于红黑树,元素有序)相比,它的核心特点是:
- 无序性:元素存储顺序与插入顺序无关,不支持按Key排序访问;
- 高效性:平均情况下,插入、删除、查找操作的时间复杂度为 O(1)(最坏情况为 O(n),取决于哈希函数质量);
- 唯一性:容器中不会存储重复元素,插入重复值会被忽略。
二、头文件与命名空间
使用 std::unordered_set 需包含头文件 <unordered_set>,并位于 std 命名空间中:
#include <unordered_set> using namespace std; // 或显式使用 std::unordered_set
三、常用方法与示例
1. 构造与析构
std::unordered_set 提供多种构造方式,满足不同初始化需求:
| 方法 | 说明 |
|---|---|
| unordered_set() | 默认构造:创建空容器 |
| unordered_set(initializer_list<T> init) | 初始化列表构造:用 {a, b, c} 初始化 |
| unordered_set(InputIt first, InputIt last) | 范围构造:用迭代器范围 [first, last) 初始化 |
| unordered_set(const unordered_set& other) | 拷贝构造 |
示例:
#include <IOStream> #include <unordered_set> #include <vector> int main() { // 1. 默认构造 unordered_set<int> us1; // 2. 初始化列表构造 unordered_set<NvPTxUS;int> us2 = {1, 2, 3, 4}; // 3. 范围构造(从vector初始化) vector<China编程;int> vec = {5, 6, 7}; unordered_set<int> us3(vec.begin(), vec.end()); // 4. 拷贝构造 unordered_set<int> us4(us2); return 0; }
2. 迭代器与遍历
std::unordered_set 提供迭代器用于遍历元素,由于无序性,遍历顺序与插入顺序无关。
| 方法 | 说明 |
|---|---|
| begin() / cbegin() | 返回指向首元素的迭代器(cbegin() 为 const 版本) |
| end() / cend() | 返回指向尾后位置的迭代器 |
示例:
unordered_set<int> us = {3, 1, 4, 1, 5}; // 重复的1会被自动js去重
// 遍历元素(顺序不确定)
for (auto it = us.begin(); it != us.end(); ++it) {
cout << *it << " "; // 可能输出:3 1 4 5
}
cout << endl;
// C++11 范围for循环(更简洁)
for (int val : us) {
cout << val << " "; // 输出顺序与上相同(同一次运行中)
}
3. 容量相关
用于判断容器状态或获取元素数量:
| 方法 | 说明 |
|---|---|
| empty() | 判断容器是否为空(空返回 true) |
| size() | 返回当前元素个数 |
| max_size() | 返回容器理论上可存储的最大元素个数(受系统限制) |
示例:
unordered_set<string> us = {"apple", "banana"};
cout << "是否为空:" << (us.empty() ? "是" : "否") << endl; // 输出:否
cout << "元素个数:" << us.size() << enChina编程dl; // 输出:2
cout << "最大容量:" << us.max_size() << endl; // 输出:约1e18(取决于系统)
4. 元素修改(插入、删除、清空)
这是 std::unordered_set 最核心的操作,用于维护容器中的元素。
| 方法 | 说明 |
|---|---|
| insert(val) | 插入元素 val,若已存在则忽略;返回 pair<iteNvPTxUSrator, bool>(迭代器指向元素,bool 表示是否插入成功) |
| insert(first, last) | 插入迭代器范围 [first, last) 中的元素 |
| erase(val) | 删除值为 val 的元素,返回删除的个数(0 或 1) |
| erase(it) | 删除迭代器 it 指向的元素,返回下一个元素的迭代器 |
| clear() | 清空所有元素 |
| swap(other) | 交换当前容器与 other 的内容 |
示例:
unordered_set<int> us;
// 插入元素
auto res1 = us.insert(10);
cout << "插入10:" << (res1.second ? "成功" : "失败") << endl; // 成功
auto res2 = us.insert(10); // 插入重复值
cout << "再次插入10:" << (res2.second ? "成功" : "失败") << endl; // 失败
// 插入多个元素
us.insert({20, 30, 40});
// 删除元素(按值)
int del_count = us.erase(20);
cout << "删除20的个数:" << del_count << endl; // 1
// 删除元素(按迭代器)
auto it = us.find(30); // 先查找元素
if (it != us.end()) {
us.erase(it); // 删除30
}
// 清空容器
us.clear();
cout << "清空后大小:" << us.size() << endl; // 0
5. 元素查找
用于判断元素是否存在或获取元素位置:
| 方法 | 说明 |
|---|---|
| find(val) | 查找值为 val 的元素,返回指向该元素的迭代器;若不存在,返回 end() |
| count(val) | 返回值为 val 的元素个数(0 或 1,因元素唯一) |
| contains(val) | C++20 新增,判断元素 val 是否存在(返回 bool),比 count() 更直观 |
示例:
unordered_set<string> fruits = {"apple", "banana", "cherry"};
// 查找元素
auto it = fruits.find("banana");
if (it != fruits.end()) {
cout << "找到:" << *it << endl; // 找到:banana
} else {
cout << "未找到" << endl;
}
// 计数(判断存在性)
if (fruits.count("orange") == 1) {
cout << "存在orange" << endl;
} else {
cout << "不存在orange" << endl; // 输出此句
}
// C++20 contains
if (fruits.contains("apple")) {
cout << "存在apple" << endl; // 输出此句
}
6. 哈希策略相关
std::unordered_set 底层依赖哈希表,以下方法用于控制哈希表的性能:
| 方法 | 说明 |
|---|---|
| load_factor() | 返回当前负载因子(元素数 / 桶数),反映哈希表的拥挤程度 |
| max_load_factor() | 返回或设置最大负载因子(默认值通常为 1.0)。当实际负载因子超过此值时,哈希表会自动扩容(重哈希) |
| rehash(n) | 强制将桶数设置为至少 n,可能触发重哈希 |
| reserve(n) | 预分配空间,确保容器可容纳 n 个元素而无需重哈希(比 rehash() 更常用) |
示例:
unordered_set<int> us;
// 预分配空间(避免频繁重哈希)
us.reserve(1000); // 确保可容纳1000个元素
// 插入元素
for (int i = 0; i < 500; ++i) {
us.insert(i);
}
cout << "当前负载因子:" << us.load_factor() << endl; // ~0.5(500/1000)
cout << "最大负载因子:" << us.max_load_factor() << endl; // 1.0
// 修改最大负载因子
us.max_load_factor(0.8);
cout << "修改后最大负载因子:" << us.max_load_factor() << endl; // 0.8
四、自定义类型的使用
std::unordered_set 存储自定义类型(如结构体)时,需满足两个条件:
- 提供哈希函数:告诉容器如何计算元素的哈希值;
- 提供相等比较函数:用于解决哈希碰撞(不同元素可能有相同哈希值)。
示例:存储自定义 Person 结构体
#include <string>
struct Person {
string name;
int age;
// 定义相等比较(用于解决哈希碰撞)
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
// 特化 std::hash 用于 Person(提供哈希函数)
namespace std {
template<> struct hash<Person> {
size_t operator()(const Person& p) const {
// 组合 name 和 age 的哈希值(简单实现)
size_t h1 = hash<string>()(p.name);
size_t h2 = hash<int>()(p.age);
return h1 ^ (h2 << 1); // 哈希组合
}
};
}
int main() {
unordered_set<Person> people;
people.insert({"Alice", 25});
people.insert({"Bob", 30});
// 查找
Person target = {"Alice", 25};
if (people.contains(target)) {
cout << "找到 Alice" << endl;
}
return 0;
}
五、与 std::set 的对比
| 特性 | std::unordered_set | std::set |
|---|---|---|
| 底层实现 | 哈希表 | 红黑树(平衡二叉树) |
| 元素顺序 | 无序 | 有序(默认升序) |
| 插入/删除/查找复杂度 | 平均 O(1),最坏 O(n) | O(log n) |
| 内存占用 | 较高(哈希表需额外空间) | 较低 |
| 适用场景 | 频繁查找、不关心顺序 | 需要有序遍历、范围查询(如 lower_bound) |
六、注意事项
- 哈希函数质量:差的哈希函数会导致大量碰撞,使性能退化到 O(n),需确保哈希值分布均匀;
- 元素不可修改:
std::unordered_set的元素是 const 类型(修改会破坏哈希表结构),若需修改,需先删除再插入; - 重哈希开销:当负载因子超过阈值时,容器会自动重哈希(重建哈希表),可能导致性能波动,可通过
reserve()提前分配空间避免; - 自定义类型要求:必须提供哈希函数和相等比较函数,否则编译报错。
到此这篇关于C++中unordered_set哈希集合的实现的文章就介绍到这了,更多相关C++ unordered_set哈希集合内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!
这篇关于C++中unordered_set哈希集合的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!