我正致力于一个效率至关重要的项目。哈希表非常有用,因为我需要根据键轻松查找节点的内存地址。我预见的唯一问题是这个哈希表需要处理多达100万个条目。据我所知,通常哈希表桶是一个链表,以便它们可以处理同一个桶中的多个条目。在我看来,有一百万个条目,这些列表将太慢。实现这样的事情的常见方法是什么。也许可以将标准链表换成跳过列表?
答案 0 :(得分:3)
如果每个桶列表有多个条目,则会失去哈希表的所有优点。使哈希表扩展到数百万个条目的常用方法是使主哈希数组可调整大小,因此即使有数百万个条目,存储桶列表仍然很短。
答案 1 :(得分:3)
如果你想要一个包含一百万个条目的哈希表,通常你至少有200万个桶。我不记得所有的统计数据(关键术语是“生日悖论”),但绝大多数的桶都有零个或一个项目。原则上,你可以非常不幸并将所有物品放在一个桶中 - 但是你必须比那些似乎每隔一天被闪电击中的人更不走运。
对于增长的哈希表,通常的技巧是以恒定的百分比增长 - 通常的教科书案例是通过将哈希表大小加倍来增长。只要哈希表中的项目数达到哈希表大小的某个比例,无论实际使用多少桶,都可以执行此操作。这为插入,删除和搜索提供了摊销的预期 O(1)性能。
哈希表的每个桶中的链表只是处理冲突的一种方式 - 在每个操作意义上不太可能,但是在重要哈希表的生命周期中,它们做发生 - 特别是当哈希表超过一半时。
链接列表不是处理冲突的唯一方法 - 关于这个主题存在大量的传说。 Walter Bright(D编程语言的开发人员)主张使用二叉树而不是链表,声称他的Dscript在这个设计选择中相对于Javascript获得了显着的性能提升。
当我问到时,他使用了简单(不平衡)二叉树,因此最坏情况下的性能与链表相同,但我猜的关键点是二叉树处理代码很简单,哈希表本身使建造大型不平衡树木的可能性非常小。
原则上,您可以轻松使用treaps,红黑树或AVL树。一个有趣的选择可能是使用splay树进行碰撞处理。但总的来说,对于一些图书馆设计师而言,这是一个小问题,也是一些需要担心的真正的痴迷。
答案 2 :(得分:1)
您可以在单个“存储桶”中使用树而不是列表。 (AVL或类似的)
编辑:好吧,Skip List也会这样做。 (而且似乎更快) - O(log n)就是你的目标。答案 3 :(得分:1)
条目总数无关紧要,只有每个桶的平均条目数(N /散列大小)。使用具有较大域(例如,20位,甚至更大)的哈希函数来确保这一点。
当然,这将占用更多内存,但就是这样,这是一种常见的内存与速度权衡。
答案 4 :(得分:0)
不确定这是否会对您有所帮助,但可能:http://memcached.org/
答案 5 :(得分:0)
如果您的密钥具有正常分布(这是一个非常大的IF),那么插入哈希表中以便耗尽哈希表中所有桶的预期数量是M * logM(自然日志,到基数e),其中M桶的数量。
很惊讶在网上找不到这个!
我已经在my blog上发布了相同内容,并使用rand()对代码进行了验证。这似乎是一个非常好的估计。