有人可以说一下流行语言如Python,Ruby如何在内部实现哈希表进行符号查找?他们使用经典的“带链接列表的数组”方法,还是使用平衡树?
我需要一个简单的(更少的LOC)和快速方法来索引用C编写的DSL中的符号。想知道其他人发现的最有效和最实用的。
答案 0 :(得分:16)
您提到的经典“哈希桶数组”用于我见过的每个实现中。
最具教育意义的版本之一是Tcl语言中的哈希实现,位于文件tcl/generic/tclHash.c中。文件中超过一半的行是详细解释所有的注释:分配,搜索,不同的哈希表类型,策略等。旁注:实现Tcl语言的代码是真的< / em>可读。
答案 1 :(得分:12)
Perl使用带有链表的数组来保存冲突。它有一个简单的启发式,可以根据需要自动加倍数组的大小。还有代码在哈希之间共享密钥以节省一点内存。您可以在过时但在“HV”下仍然相关的Perl Illustrated Guts中阅读它。如果您真正喜欢冒险,可以深入了解hv.c。
哈希算法过去非常简单,但现在使用Unicode可能要复杂得多。由于该算法是可预测的,因此存在DoS攻击,攻击者生成的数据会导致哈希冲突。例如,作为POST数据发送到网站的大量密钥列表。 Perl程序可能会将其拆分并将其转储为哈希值,然后将其全部推入一个桶中。得到的散列是O(n)而不是O(1)。在服务器上抛出大量POST请求,可能会阻塞CPU。因此,Perl现在用一些随机数据来扰乱哈希函数。
您还可以查看how Parrot implements basic hashes,它比Perl 5实现明显不那么可怕。
至于“最有效和最实用”,请使用其他人的哈希库。为了上帝的缘故,不要自己写一个用于生产用途。那里已经有很多强大而高效的产品。
答案 2 :(得分:8)
Lua表使用utterly ingenious implemenation,其中任意键的行为类似于“数组桶”,但如果使用连续的整数作为键,则它具有与数组相同的表示和空间开销。在实现中,每个表都有一个哈希部分和一个数组部分。
我认为这很酷: - )
答案 3 :(得分:4)
平衡树会破坏哈希表的目的,因为哈希表可以提供(摊销)常量时间的查找,而平衡树上的平均查找是O(log(n))。
如果你有足够的存储桶,那么单独链接(带有链表的数组)确实很有效,而你的链表实现使用池分配器而不是malloc()来自堆中的每个节点。我发现它在适当调整时与其他任何技术一样高效,并且编写起来非常简单快捷。尝试从源数据的1/8开始尝试。
您还可以使用open addressing进行二次或多项式探测,as Python does。
答案 4 :(得分:4)
Attractive Chaos有一个comparison of Hash Table Libraries和一个update。 源代码可用,它使用C和C ++
答案 5 :(得分:2)
如果您可以阅读Java
,则可能需要查看其各种地图实施的源代码,尤其是HashMap
,TreeMap
和ConcurrentSkipListMap
。后两者保持按键排序。
Java HashMap
使用您在每个桶位置链接的标准技术。它使用相当弱的32位哈希码并将密钥存储在表中。 Numerical Recipes的作者还提供了一个示例(在C中)的哈希表基本上像Java的结构,但其中(a)你从一个数组中分配桶列表的节点,(b)你使用更强大的64位哈希代码并省去在表格中存储密钥。
答案 6 :(得分:1)
Crashworks的意思是......
哈希表的目的是持续时间查找,添加和删除。在算法方面,所有操作的操作都是O(1)摊销。 而如果您使用树...最坏情况下的操作时间将是平衡树的O(log n)。 N是节点数。但是,我们真的将哈希实现为树吗?