cpp►STL容器->哈希容器->unordered_set
Posted itzyjr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cpp►STL容器->哈希容器->unordered_set相关的知识,希望对你有一定的参考价值。
目录
描述
std::unordered_set
template <class Key, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Alloc = allocator<Key>>
class unordered_set;
unordered_set是不按特定顺序存储唯一元素的容器,它允许根据元素的值快速检索单个元素。
在无序的集合中,元素的值同时是它的键,唯一地标识它。键是不可变的,因此,无序集合中的元素一旦在容器中就不能被修改,但是它们可以被插入和删除。
在内部,unordered_set集合中的元素不是按任何特定顺序排序的,而是根据它们的散列值组织到储存区(buckets)中,以允许直接通过它们的值快速访问单个元素(平均时间复杂度不变)。
unordered_set容器比集合容器通过其键访问单个元素的速度更快,尽管它们通过元素的子集进行范围迭代的效率通常较低。
容器中的迭代器至少是正向迭代器。
无序容器使用哈希表(hash tables)组织它们的元素,哈希表允许通过它们的键快速访问元素。
< functional > std::hash
template <class T> struct hash;
一元函数对象类,标准库中定义和使用的默认哈希函数。
函数调用返回其参数的哈希值:哈希值是仅依赖于其参数的值,对于同一参数(对于给定的程序执行)始终返回相同的值。
< functional > std::equal_to
template <class T> struct equal_to;
二元函数对象类,其调用返回其两个参数比较是否相等(由operator==返回)。
一般来说,函数对象是定义了成员function operator()的类的实例。此成员函数允许对象使用与函数调用相同的语法。
其定义与以下行为相同:
template <class T>
struct equal_to {
bool operator() (const T& x, const T& y) const {
return x == y;
}
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
模板参数(Template parameters)
- Key
元素的类型。unordered_set集合中的每个元素也由该值唯一标识。别名为成员类型unordered_set::key_type和unordered_set::value_type。 - Hash
一个一元函数对象类型,它以与元素类型相同的对象作为参数,并基于它返回一个类型为size_t的唯一值。这可以是实现了函数调用运算符的类,也可以是指向函数的指针。默认为hash<Key>,它返回一个哈希值,冲突概率(probability of collision)接近1.0/std::numeric_limits<size_t>::max()。
unordered_set对象使用此函数返回的哈希值在内部组织其元素,从而加快查找单个元素的过程。
别名为成员类型unordered_set::hasher。 - Pred
一个二元谓词,它接受两个与元素类型相同的参数并返回布尔值。表达式pred(a, b),其中pred是这种类型的对象,a和b是键值,如果a被认为等同于b,则应返回true。这可以是实现了函数调用运算符的类,也可以是指向函数的指针。默认为equal_to(Key),它返回与equal-to运算符(a==b)相同的值。
unordered_set对象使用这个表达式来确定两个元素键是否相等。unordered_set容器中的两个元素都不能有使用此谓词生成true的键。
别名为成员类型unordered_set::key_equal。 - Alloc
用于定义存储分配模型的分配器对象的类型。默认情况下,使用allocator类模板,它定义了最简单的内存分配模型,并且与值无关。
别名为成员类型unordered_set::allocator_type。
成员类型(Member types)
成员类型 | 定义 | 备注 |
---|---|---|
key_type | 第一个模板参数(Key) | |
value_type | 第一个模板参数(Key) | 与key_type相同 |
hasher | 第二个模板参数(Hash) | 默认为:hash<key_type> |
key_equal | 第三个模板参数(Pred) | 默认为:equal_to<key_type> |
pointer | Alloc::pointer | 对于默认allocator,为:value_type* |
local_iterator | 一个针对const value_type的forward iterator(前向迭代器) | 可转换为const_local_iterator |
成员函数(Member functions)
构造函数:
// constructing unordered_sets
#include <iostream>
#include <string>
#include <unordered_set>
template<class T>
T cmerge(T a, T b) {
T t(a);
t.insert(b.begin(), b.end());
return t;
}
int main() {
std::unordered_set<std::string> first;// empty
std::unordered_set<std::string> second({ "red","green","blue" });// init list
std::unordered_set<std::string> third({ "orange","pink","yellow" });// init list
std::unordered_set<std::string> fourth(second);// copy
std::unordered_set<std::string> fifth(cmerge(third, fourth));// move
std::unordered_set<std::string> sixth(fifth.begin(), fifth.end());// range
std::cout << "sixth contains:";
for (const std::string& x : sixth)
std::cout << " " << x;
return 0;
}
sixth contains: pink yellow red green orange blue
迭代器(Iterators)
- begin、end
container iterator (1) iterator begin() noexcept;
bucket iterator (2) local_iterator begin(size_type n);
对于bucket iterator (2),参数n表示bucket的编号,它应该小于bucket_count。
它是一个可选参数,用于更改此成员函数的行为:如果设置了,则检索到的迭代器将指向编号为n的bucket的第一个元素,否则将指向容器container的第一个元素。
成员类型size_type是无符号整数类型。
Buckets
- bucket_count
size_type bucket_count() const noexcept;
bucket是容器内部哈希表中的一个槽,元素根据其哈希值被分配到该槽中。
bucket的数量直接影响容器哈希表的负载因子(load factor)(从而影响冲突的概率)。容器会自动增加bucket的数量,以将负载系数保持在特定阈值(其最大负载系数max_load_factor)以下,从而导致每次需要增加bucket的数量时重新刷新。
// unordered_set::bucket_count
#include <iostream>
#include <string>
#include <unordered_set>
int main() {
std::unordered_set<std::string> myset =
{ "Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune" };
unsigned n = myset.bucket_count();
std::cout << "myset has " << n << " buckets.\\n";
for (unsigned i = 0; i < n; ++i) {
std::cout << "bucket #" << i << " contains:";
for (auto it = myset.begin(i); it != myset.end(i); ++it)
std::cout << " " << *it;
std::cout << "\\n";
}
return 0;
}
一种可能的输出:
myset has 11 buckets.
bucket #0 contains:
bucket #1 contains: Venus
bucket #2 contains: Jupiter
bucket #3 contains:
bucket #4 contains: Neptune Mercury
bucket #5 contains:
bucket #6 contains: Earth
bucket #7 contains: Uranus Saturn
bucket #8 contains: Mars
bucket #9 contains:
bucket #10 contains:
另一种可能的输出:
myset has 8 buckets.
bucket #0 contains: Mars
bucket #1 contains:
bucket #2 contains: Neptune
bucket #3 contains:
bucket #4 contains:
bucket #5 contains: Uranus
bucket #6 contains: Saturn Jupiter Venus Mercury
bucket #7 contains: Earth
- max_bucket_count
size_type max_bucket_count() const noexcept;
返回unordered_set容器可以拥有的最大bucket数目。
// unordered_set limits
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> myset;
std::cout << "max_size = " << myset.max_size() << std::endl;
std::cout << "max_bucket_count = " << myset.max_bucket_count() << std::endl;
std::cout << "max_load_factor = " << myset.max_load_factor() << std::endl;
return 0;
}
max_size = 357913941
max_bucket_count = 536870911
max_load_factor = 1
- bucket_size
size_type bucket_size(size_type n) const;
返回在编号为n的bucket中的元素个数。
// unordered_set::bucket_size
#include <iostream>
#include <string>
#include <unordered_set>
int main() {
std::unordered_set<std::string> myset =
{ "red", "green", "blue", "yellow", "purple", "pink" };
unsigned nbuckets = myset.bucket_count();
std::cout << "myset has " << nbuckets << " buckets:\\n";
for (unsigned i = 0; i < nbuckets; ++i) {
std::cout << "bucket #" << i << " has " << myset.bucket_size(i) << " elements.\\n";
}
return 0;
}
可能的一种输出:
myset has 8 buckets:
bucket #0 has 0 elements.
bucket #1 has 1 elements.
bucket #2 has 0 elements.
bucket #3 has 0 elements.
bucket #4 has 2 elements.
bucket #5 has 2 elements.
bucket #6 has 0 elements.
bucket #7 has 1 elements.
- bucket
size_type bucket(const key_type& k) const;
返回值为k的元素所在的bucket编号。
bucket被编号为0~(bucket_count-1)。
// unordered_set::bucket
#include <iostream>
#include <string>
#include <unordered_set>
int main() {
std::unordered_set<std::string> myset =
{ "water","sand","ice","foam" };
for (const std::string& x : myset) {
std::cout << x << " is in bucket #" << myset.bucket(x) << std::endl;
}
return 0;
}
可能的一种输出:
ice is in bucket #0
water is in bucket #0
sand is in bucket #3
foam is in bucket #4
哈希策略(Hash policy)
- load_factor、max_load_factor
负载系数是容器中元素的数量(size)与bucket的数量(bucket_count)之间的比率:
load_factor = size / bucket_count
负载因子影响哈希表中的冲突概率(即两个元素位于同一个bucket中的概率)。容器会自动增加bucket的数量,以将负载系数保持在特定阈值(其最大负载系数max_load_factor)以下,这导致在每次需要扩展时重新刷新。
// unordered_set hash table stats
#include <iostream>
#include <unordered_set>
int main() {
std::unordered_set<int> myset;
std::cout << "size = " << myset.size() << std::endl;
std::cout << "bucket_count = " << myset.bucket_count() << std::endl;
std::cout << "load_factor = " << myset.load_factor() << std::endl;
std::cout << "max_load_factor = " << myset.max_load_factor() << std::endl;
return 0;
}
Possible output:
size = 0
bucket_count = 8
load_factor = 0
max_load_factor = 1
- rehash
void rehash(size_type n);
设置容器哈希表中bucket的最小数量为n。
如果n大于容器中当前的bucket数量(bucket_count),则强制重新哈希(rehash)。新的bucket数可以等于或大于n。如果n小于容器中当前的bucket数量,该函数可能对bucket数量没有影响,并且可能不会强制重新哈希。
rehash是哈希表的重建:容器中的所有元素根据它们的哈希值重新排列到新的一组bucket中。这可能会改变容器中元素的迭代顺序。
在一个操作中,当容器的负载系数超过其最大负载系数时(load_factor>max_load_factor),容器会自动执行rehash。
请注意,此函数期望以bucket数作为参数。存在一个类似的函数unordered_set::reserve,它期望以容器中的元素个数作为参数。 - reserve
void reserve(size_type n);
将容器中的bucket的数量(bucket_count)设置为最适合包含至少n个元素。
观察者(Observers)
- hash_function
hasher hash_function() const;
返回unordered_set容器使用的哈希函数对象。
哈希函数是一个一元函数,它以key_type类型的对象作为参数,并基于它返回类型为size_t的唯一值。
// unordered_set::hash_function
#include <iostream>
#include <string>
#include <unordered_set>
typedef std::unordered_set<std::string> stringset;
int main() {
stringset myset;
stringset::hasher fn = myset.hash_function();
std::cout << "that: " << fn("that") << std::endl;
std::cout << "than: " << fn("than") << std::endl;
return 0;
}
that: 3407360812
than: 3843578906
- key_eq
key_equal key_eq() const;
返回unordered_set容器使用的键等价比较谓词。
键等价比较是一个谓词,它将两个元素的值作为参数,并返回一个bool值,指示它们是否被认为是等价的。
成员类型key_equal是容器使用的键等价比较谓词的类型,在unordered_set中定义为其第三个模板参数(Pred)的别名。
// unordered_set::key_eq
#include <iostream>
#include <string>
#include <unordered_set>
int main() {
std::unordered_set<std::string> myset;
bool case_insensitive = myset.key_eq()("checking", "CHECKING");
std::cout << "myset.key_eq() is ";
std::cout << (case_insensitive ? "case insensitive" : "case sensitive");
std::cout << std::endl;
return 0;
}
myset.key_eq() is case sensitive
以上是关于cpp►STL容器->哈希容器->unordered_set的主要内容,如果未能解决你的问题,请参考以下文章