使用链哈希实现动态哈希表

Implementation of dynamic hash table using chain hashing

本文关键字:动态 哈希表 实现 哈希      更新时间:2023-10-16

我正在尝试使用链哈希实现一个动态哈希表(数组中的每个元素都是一个链表)。从复杂性的角度来看,我想知道以下哪种可能性更好:1.当数组已满时,我应该将数组大小增加一倍,这意味着每个链表至少有一个元素。2.当我总共有N个元素(在所有链表中)时,我应该将数组大小增加一倍,其中N是数组大小。

大量的散列表实现,包括C++标准中的几个(unordered_set,unordered_map)。

为了回答您的问题,当元素计数达到N时,最好将bin计数(内部数组)增加一倍。否则会更困难,也更耗时(查看是否所有bin都已满)。

您需要保留一个包含元素计数的成员。

您不需要担心用户使用像{ return 0;}这样的糟糕哈希函数。

就复杂性而言,它们都是一样的。哈希表的复杂度是按平均情况分摊的O(1)给出的,因为一旦你有了一个好的哈希函数,哈希冲突就会归结为运气问题。不管你做什么,任何哈希表最坏的复杂度都是O(N)

也就是说,有用的实现基于负载因子来调整大小,负载因子是总元素和存储桶数量("数组大小")之间的比率。等到每个bucket至少有一个条目时,会经常导致次优行为。但是负载因子1(N个桶中的N个元素)可能太高;我见过的大多数实现默认为0.7左右(10个bucket有7个元素),并且通常让用户配置负载因子(请同时参阅C++和Java)。这是内存与速度的交易,哈希表通常都是关于速度的。通常,只有评测才会显示任何给定程序的正确值。

此外,尺寸不需要加倍。典型的vector实现在每次调整大小时都会将其大小增加50%或70%,因为在真实世界的应用程序上进行的大规模测试表明,这是比加倍更好的速度/内存权衡。当然,类似的事情也适用于哈希表,尽管这也需要进行分析。