无序映射的实现

Posted

技术标签:

【中文标题】无序映射的实现【英文标题】:Implementation of an Unordered Map 【发布时间】:2021-05-02 10:28:38 【问题描述】:

我正在尝试理解无序映射和散列。据我了解,无序映射内部有一个哈希函数,它接受一个类型为 T 的对象,并返回一个 int,然后使用 int 作为内部数组的索引。它在数组位置使用类型为 T 的对象的 List,因此如果该位置已经存在某些内容,则将添加的内容插入到 List 中。

从概念上讲,使用 Set 代替 List 会提高效率吗? (也许以某种方式二进制搜索和排序的集合有助于拥有一个列表)

或者也许是一个向量而不是列表? (也许随机访问对列表有帮助。)

【问题讨论】:

这个被关闭的副本并没有解决这里的问题,即“使用集合[或向量]而不是链表[在每个桶中]会提高效率吗?”。跨度> 【参考方案1】:

数据类型应该无关紧要,因为在大多数情况下,散列索引处的容器只包含零个或一个元素。如果你经常在那里有很多元素,那么哈希映射无论如何都会降低性能。对此的补救措施是调整初始数组的大小,std::unordered_map<> 会自行调整。但是,如果您有一个不好的哈希函数导致许多哈希冲突,则切换哈希函数对于正确操作是必要的。

【讨论】:

【参考方案2】:

如果在同一个存储桶中经常有很多个冲突,那么使用集合比使用列表更有效,并且确实出于这个原因,一些 Java 哈希表实现采用了集合。向量不能用于std::unordered_mapstd::unordered_set 实现,因为当它们超过其容量时需要重新分配到不同的内存区域,而标准要求无序容器中的元素永远不会被其他操作移动容器。

也就是说,哈希表的本质是 - 具有高质量的哈希函数 - 在特定存储桶中碰撞的元素数量的统计分布仅与负载因子有关。如果你不能相信碰撞不会失控,也许你不应该使用那个散列函数。

一些细节:标准库无序容器的默认 max_load_factor()load_factor()size()bucket_count() 的比率)为 1.0,并且具有强大的伪随机散列函数,它们将有 1 /e ~= 36.8% 的桶是空的,有一个元素,一半有 2 个元素(~18.4%),三分之一有 3 个元素(~6.13%),四分之一有 4 个元素(~1.53 %),五分之一的元素(~0.3%),六分之一的元素(~0.05%)。正如您所希望看到的,必须搜索许多元素是非常罕见的(即使在哈希表处于其最大负载因子的最坏情况下),因此列表方法通常就足够了。

【讨论】:

以上是关于无序映射的实现的主要内容,如果未能解决你的问题,请参考以下文章

使用c ++无序+映射的无效操作数

我们如何在 C++ 中的无序映射中分配变量并更新它们?

Go语言实战之映射的内部实现和基础功能

Go语言实战之映射的内部实现和基础功能

使用java实现面向对象 第六章

Map和TreeMap的特点