不确定无序映射是如何工作的

Not sure how unordered_map works

本文关键字:工作 何工作 无序 映射 不确定      更新时间:2023-10-16

我有点困惑无序映射是如何工作的,什么是bucket以及如何管理thet。

从这篇博客文章来看,unrdered_map是向量中的向量。

我的问题是:

  • 假设bucket是"内部"向量是否正确
  • 由于每个bucket(向量)可以包含多个元素,由哈希表上的哈希冲突("外部"向量)给出,并且由于我们必须扫描这个内部向量(在线性时间内),因此假设我们必须在密钥类型上定义equal方法(依赖于哈希运算符)才能找到bucket中的密钥,这正确吗
  • 默认情况下,外部向量(哈希表)的大小是多少
  • 默认情况下,内部向量大小是多少
  • 如果一个bucket中的元素数量过大,会发生什么?换言之,当重洗发生时

很抱歉出现这些问题,但我没有找到任何详细的解释来解释这个结构是如何工作的(例如在cppreference.com上)。

std::unordereded_map是标准的C++哈希表。它曾经在STL中被称为hash_map,但在1998年STL的许多接口被合并到C++中时,它错过了机会。到2011年,许多库都有了自己的hash_map。C++不得不选择另一个名称(我认为"无序"是一个很好的选择;假设哈希表中的顺序是错误的常见来源)。

假设bucket是"内部"向量是否正确?

不,它既不正确(与迭代器无效要求不兼容),也很危险(在这种假设下,您最终可能会减去指向同一bucket中元素的指针)。

在现实生活中,bucket是链表;例如

  • LLVM libc++unordered_map是__hash_node的链表数组的unique_ptr
  • GNU libstdc++unordered_map是指向_Hash_node链表数组的指针

假设我们必须在密钥类型上定义equal方法(依赖于hash运算符)才能在bucket中找到密钥,这正确吗?

是的,在bucket中定位密钥正是std::unordered_map的第四个模板参数的作用(当然,不需要从字面上调用"密钥类型上的相等方法")

默认情况下,外部向量(哈希表)的大小是多少?

不存在"外部矢量"。默认构造的std::unordered_map的bucket数量是由实现定义的,您可以使用bucket_count查询它。

默认情况下,内部向量大小是多少?

不存在"内部矢量"。任何给定bucket的大小等于当前放置在bucket中的元素数。您可以使用bucket_size 进行查询

如果一个bucket中的元素数量过大,会发生什么?换言之,当重洗发生时?

如果一个bucket中的元素数量过大,则不会发生任何事情。但是,如果每个bucket的平均元素数(也称为load_factor)超过max_load_factor,则会发生重新散列(例如插入时)

这可能有助于您理解bucket:http://www.cplusplus.com/reference/unordered_map/unordered_map/bucket_count/http://www.cplusplus.com/reference/unordered_map/unordered_map/max_load_factor/

但一般来说,是的,桶有点像内部向量。它需要一个相等运算符(或谓词)来区分具有与您建议的相同哈希的键。

存储桶的初始数量可能为0。它可以通过rehash()或reserve()进行设置(它们的语义略有不同。)

http://www.cplusplus.com/reference/unordered_map/unordered_map/rehash/

在理想情况下,每个bucket只有一个项目。您可以使用bucket_size进行检查。当负载系数(总项目数与存储桶数)变高时,它会自动重新灰。

默认情况下,它将以1:1的荷载系数为目标。如果散列函数是好的,这可能会持续到插入max_bucket_count项为止。

请记住,具体实施方式可能会有所不同。每个实现(例如,来自不同平台或标准库)实际上只需要具有正确的语义。

如果这些答案对你的程序很重要,你可以像我描述的那样查询这些值。如果你只是想了解它,在一些测试场景中查询它们,它可能会变得更清楚。