C++ 中的unordered_set容器
什么是unordered_set?
unordered_set
是C++11标准引入的一种关联容器,它存储唯一的元素,并允许通过元素值快速检索元素。与有序的set
容器不同,unordered_set
内部使用哈希表实现,因此:
- 元素在容器中没有特定的顺序
- 查找、插入和删除操作的平均时间复杂度为O(1)
- 不允许存储重复元素
提示
unordered_set
是需要频繁查找、插入和删除操作,且不关心元素顺序时的理想选择。
头文件和命名空间
要使用unordered_set
,需要包含相应的头文件:
#include <unordered_set>
// 该容器位于std命名空间中
using namespace std; // 或者使用std::unordered_set
基本用法
创建unordered_set
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
// 创建空的unordered_set
unordered_set<int> numbers;
// 使用初始化列表创建
unordered_set<string> fruits = {"apple", "banana", "orange"};
// 使用迭代器范围创建
int arr[] = {10, 20, 30, 40, 50};
unordered_set<int> numSet(arr, arr + 5);
// 使用拷贝构造函数
unordered_set<string> fruitsCopy(fruits);
return 0;
}
基本操作
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
unordered_set<int> numbers;
// 插入元素
numbers.insert(10);
numbers.insert(20);
numbers.insert(30);
numbers.insert(10); // 重复元素不会被插入
// 打印元素数量
cout << "Size: " << numbers.size() << endl; // 输出: Size: 3
// 检查元素是否存在
if (numbers.find(20) != numbers.end()) {
cout << "20 exists in the set" << endl;
}
// 使用count函数检查元素(对于set,结果只会是0或1)
cout << "30 count: " << numbers.count(30) << endl; // 输出: 30 count: 1
cout << "40 count: " << numbers.count(40) << endl; // 输出: 40 count: 0
// 删除元素
numbers.erase(20);
// 遍历元素
cout << "Elements: ";
for (int num : numbers) {
cout << num << " ";
}
cout << endl; // 输出可能是: Elements: 30 10 (顺序不确定)
// 清空容器
numbers.clear();
cout << "After clear, size: " << numbers.size() << endl; // 输出: After clear, size: 0
return 0;
}
哈希函数和桶
unordered_set
使用哈希表实现,我们可以查看和控制其内部结构:
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
unordered_set<string> words = {"hello", "world", "programming", "c++", "container"};
// 查看桶的数量
cout << "Bucket count: " << words.bucket_count() << endl;
// 查看负载因子
cout << "Load factor: " << words.load_factor() << endl;
// 查看每个桶中的元素数量
cout << "Elements in buckets: " << endl;
for (size_t i = 0; i < words.bucket_count(); ++i) {
cout << "Bucket " << i << ": " << words.bucket_size(i) << " elements" << endl;
}
// 查看特定元素在哪个桶
cout << "\"c++\" is in bucket: " << words.bucket("c++") << endl;
// 手动调整桶的数量
words.rehash(20);
cout << "After rehash, bucket count: " << words.bucket_count() << endl;
return 0;
}
输出示例(具体值可能会不同):
Bucket count: 8
Load factor: 0.625
Elements in buckets:
Bucket 0: 1 elements
Bucket 1: 1 elements
Bucket 2: 0 elements
Bucket 3: 1 elements
Bucket 4: 1 elements
Bucket 5: 0 elements
Bucket 6: 1 elements
Bucket 7: 0 elements
"c++" is in bucket: 4
After rehash, bucket count: 23
自定义类型作为元素
要将自定义类型用作unordered_set
中的元素,需要提供哈希函数和相等性比较函数:
#include <iostream>
#include <unordered_set>
#include <string>
using namespace std;
// 自定义类型
struct Person {
string name;
int age;
// 相等性比较
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
// 为Person类型定义哈希函数
namespace std {
template<>
struct hash<Person> {
size_t operator()(const Person& p) const {
return hash<string>()(p.name) ^ hash<int>()(p.age);
}
};
}
int main() {
unordered_set<Person> people;
// 添加一些Person对象
people.insert({"Alice", 25});
people.insert({"Bob", 30});
people.insert({"Charlie", 22});
// 查找
Person searchPerson = {"Bob", 30};
if (people.find(searchPerson) != people.end()) {
cout << "Found Bob, age 30" << endl;
}
// 遍历
for (const auto& person : people) {
cout << person.name << ", " << person.age << endl;
}
return 0;
}
性能特性
unordered_set
的特性和性能对比如下:
与set
对比:
特性 | unordered_set | set |
---|---|---|
实现方式 | 哈希表 | 红黑树 |
元素顺序 | 无序 | 有序 |
查找/插入/删除平均复杂度 | O(1) | O(log n) |
查找/插入/删除最坏复杂度 | O(n) | O(log n) |
内存占用 | 较高 | 适中 |
迭代器失效情况 | 仅当删除元素时 | 仅当删除元素时 |
警告
当哈希函数质量较差或数据分布不均匀时,unordered_set
可能会退化为O(n)的性能表现。