C++标准模板库中的无序集
unordered_set 是一种无序关联容器,在哈希表中使用哈希函数将键散列到哈希表的索引中,因此插入始终是随机的。所有 unordered_set 上的操作在平均情况下都需要常数时间 O(1) ,在最坏情况下可能需要线性时间 O(n) ,这取决于内部使用的哈希函数,但实际上它们的表现非常好,通常提供一个常数时间的查找操作。
unordered_set可以包含任何类型的键-预定义或用户定义数据结构,但所有键必须是唯一的。它在< unordered_set >头文件中定义为 std::unordered_set 类。
语法:
std::unordered_set<data_type> name;
在std::unordered_set中,定义了许多函数,其中最常用的函数是:
- size()和empty()用于容量。
- find()用于搜索关键字。
- insert()和erase()用于修改。
示例:
// C++程序演示了unordered_set的各种功能
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 声明用于存储字符串数据类型的set
unordered_set<string> stringSet;
// 将各种字符串插入,重复的字符串只会存储一次
stringSet.insert("code");
stringSet.insert("in");
stringSet.insert("c++");
stringSet.insert("is");
stringSet.insert("fast");
string key = "slow";
// 如果未找到关键字,find()则返回end迭代器;否则,返回到关键字的迭代器
if (stringSet.find(key) == stringSet.end())
cout << key << " not found" << endl << endl;
else
cout << "Found " << key << endl << endl;
key = "c++";
if (stringSet.find(key) == stringSet.end())
cout << key << " not found\n";
else
cout << "Found " << key << endl;
cout << "\nAll elements : ";
unordered_set<string>::iterator itr;
for (itr = stringSet.begin(); itr != stringSet.end();
itr++)
cout << (*itr) << endl;
}
输出
slow not found
Found c++
All elements : is
fast
c++
in
code
find()、insert()和erase()函数平均需要一个恒定的时间。如果在集合中没有关键字,find()函数会返回end()迭代器,否则返回到关键字的迭代器。迭代器作为指向关键字值的指针,因此我们可以通过使用*运算符来解除引用并获取关键字。
我们还可以看到输出的顺序混乱,因为没有特定的顺序来存储unordered_set中的数据。
注意: unordered_set只允许唯一的关键字,而对于重复的关键字应该使用unordered_multiset。
C++STL中的set vs unordered_set
Set | 无序集合 |
---|---|
Set是一组有序的唯一键序列。 | 无序集合是一种可以按任意顺序存储键的集合,因此是无序的。 |
Set是作为平衡树结构实现的,可以通过特定的树遍历方式来维护元素之间的顺序。 | 无序集合实现为哈希表,因为我们不必担心任何顺序。 |
Set操作的时间复杂度为O(log n)。 | 基本Set操作的时间复杂度是O(1)。 |
在无序集合上的实际问题
给定一个整数数组(列表),找出其中所有的重复项(假设重复项是一个由随机人猜测的相同的数字,在实验中)。
输入:
arr[] = {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5}
输出:
重复项为:5 2 1
例子:
//使用unordered_set从数组中找到重复
//C++程序
#include <bits/stdc++.h>
using namespace std;
//使用unordered_set在arr[0…n-1]中打印重复项
void printDuplicates(int arr[], int n)
{
//声明unordered sets用于检查和存储
//重复
unordered_set<int> intSet;
unordered_set<int> duplicate;
//循环遍历数组元素
for (int i = 0; i < n; i++) {
//如果元素不存在则插入该元素
if (intSet.find(arr[i]) == intSet.end())
intSet.insert(arr[i]);
//如果元素已经存在,则插入到重复集
else
duplicate.insert(arr[i]);
}
//打印结果
cout << "重复项为:";
unordered_set<int>::iterator itr;
//Iterator itr从begin()到end()循环
for (itr = duplicate.begin(); itr != duplicate.end();
itr++)
cout << *itr << " ";
}
//Driver code
int main()
{
int arr[] = { 1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5 };
int n = sizeof(arr) / sizeof(int);
printDuplicates(arr, n);
return 0;
}
输出
重复项为:5 2 1
时间复杂度:O(n log n)
辅助空间:O(n)
std::unordered_set成员方法
以下表格包含std::unordered_set类的所有成员函数:
函数名称 | 函数描述 |
---|---|
insert() | 在无序集合容器中插入一个新的 {element}。 |
begin() | 返回指向无序集合容器中第一个元素的迭代器。 |
end() | 返回指向“过去-结束”的元素的迭代器。 |
count() | 统计无序集合容器中特定元素的出现次数。 |
find() | 在容器中查找一个元素。 |
clear() | 删除无序集合中的所有元素并清空容器。 |
cbegin() | 返回指向无序集合容器中第一个元素的const_iterator。 |
cend() | 返回指向无序集合容器或其Buckets中“过去-结束”的元素的const_iterator。 |
bucket_size() | 返回无序集合容器中特定Bucket中存在的元素总数。 |
erase() | 删除单个元素或从开始(包括)到结束(不包括)范围内的一系列元素。 |
size() | 返回无序集合容器中元素的数量。 |
swap() | 交换两个无序集合容器的值。 |
emplace() | 在无序集合容器中插入一个元素。 |
max_size() | 返回无序集合容器可以容纳的最大元素数量。 |
empty() | 检查无序集合容器是否为空。 |
equal_range | 返回包括所有等于给定值的元素的范围。 |
operator= | 将一个无序集合复制(或移动)到另一个无序集合中,unordered_set::operator=是相应的操作函数。 |
hash_function() | 这个哈希函数是一个一元函数,只接受一个参数,并根据它返回一个唯一的size_t类型的值。 |
reserve() | 用于请求无序集合的容量变化。 |
bucket() | 返回特定元素的Bucket编号。 |
bucket_count() | 返回无序集合容器中存在的Bucket总数。 |
load_factor() | 返回无序集合容器中的当前负载因子。 |
rehash() | 将无序集合的容器中的Bucket数设置为给定大小或更大。 |
max_load_factor() | 返回(或设置)无序集合容器的当前最大负载因子。 |
emplace_hint() | 如果要插入的值是唯一的,则仅使用给定提示将新元素插入无序集合中。 |
operator | ‘’是C++ STL中的一个运算符,用于在两个无序集合之间执行相等比较操作,unordered_set::operator是相应的操作函数。 |
key_eq() | 根据比较返回一个布尔值。返回无序集合使用的键等价比较谓词。 |
operator!= | != 是 C++ STL 中的一个关系运算符,用于比较无序集合容器之间的相等和不相等。 |
max_bucket_count() | 查找 unordered_set 可能具有的最大桶数。 |