我试图了解HAMT的细节。我只需要了解implemented one myself in Java。我熟悉Tries,我认为我得到了HAMT的主要概念。
基本上,
两种类型的节点:
键/值
Key Value Node:
K key
V value
索引
Index Node:
int bitmap (32 bits)
Node[] table (max length of 32)
(0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-31)
注意:最后一步(第7步)只有2位。 integer==5 bitmap==00001
integer==6 bitmap==0101010101 index==3
我不太了解的部分是碰撞检测和缓解。在链接的论文中,他提到了它:
然后将现有密钥插入新的子哈希表中 添加了新密钥。每次使用5个比特的哈希值 碰撞概率降低1/32。偶尔 可以消耗整个32位散列,并且必须计算新的散列 为了确定两把钥匙。
如果我要计算一个“新”哈希并将该对象存储在该新哈希中;你怎么能够在结构中查找对象?在进行查找时,它不会生成“初始”哈希而不是“重新计算哈希”。
我一定错过了什么......
BTW:HAMT表现相当不错,它在我的测试中位于哈希映射和树形图之间。
Data Structure Add time Remove time Sorted add time Sorted remove time Lookup time Size
Java's Hash Map 38.67 ms 18 ms 30 ms 15 ms 16.33 ms 8.19 MB
HAMT 68.67 ms 30 ms 57.33 ms 35.33 ms 33 ms 10.18 MB
Java's Tree Map 86.33 ms 78 ms 75 ms 39.33 ms 76 ms 8.79 MB
Java's Skip List Map 111.33 ms 106 ms 72 ms 41 ms 72.33 ms 9.19 MB
答案 0 :(得分:4)
我认为你可能错过了论文的两个部分。第一个是紧接在你引用的位之前的位:
或者密钥将与现有密钥冲突。在哪种情况下现有的密钥 必须用子哈希表和现有密钥的下一个5位哈希替换 计算。如果仍然存在碰撞,则重复该过程直到没有碰撞 发生。
因此,如果表中有对象A并且添加了碰撞的对象B,则其键冲突的单元格将成为指向另一个子表的指针(它们不会发生冲突)。
接下来,您链接的论文的第3.7节描述了当您运行前32位结束时生成新哈希的方法:
散列函数是为了提供32位散列而定制的。算法要求 散列可以扩展到任意数量的位。这完成了 重新组合键与表示trie级别的整数相结合,为零 根。因此,如果两个键确实提供相同的初始哈希,则rehash具有 进一步碰撞的概率为1 ^ 2 32。
如果这似乎没有解释任何问题,那么我会更详细地扩展这个答案。
答案 1 :(得分:2)
HAMT是一个伟大且高性能的结构,特别是当需要不可变对象时,即每次修改后都会创建一个新的数据结构副本!
至于关于哈希冲突的问题,我找到了一个C#实现implementation (现在有错误),它显示了它是如何工作的:在每次哈希冲突时,密钥被重新填充,递归地重试查找,直到达到最大迭代次数。
目前,我还在函数式编程环境中学习HAMP并学习现有代码。在Haskell as Data.HshMap和Clojure as PersistenceHashMap中有几种HAMT的参考实现。
网上还有一些其他更简单的实现不处理冲突,但它们对理解这个概念很有用。它们位于Haskell和OCaml
我找到了一个nice summary article article来描述HAMT的图片以及Phil Bagwell对原始research papers的链接。
相关要点:
在F#中实现HAMT时,我注意到描述here的popCount函数实现非常重要,与链接中下一个答案中描述的朴素实现相比,它提供了10-15%。不是很好,但免费的午餐。
当密钥可以是整数并且它们实现相关的Haskell port to F#时,相关的IntMap结构(PATRICIA/Radix及其trie)非常好。
我相信所有这些实现都非常适合在这些例子中学习有效的不可变数据结构和功能语言 - 它们真的很闪耀!
答案 2 :(得分:1)
如果我要计算一个“新”哈希值并将该对象存储在该新哈希值上 散列;你怎么能够在中找到对象? 结构体?在查找时,它不会生成“初始” 哈希而不是“重新计算的哈希”。
在查找时,使用初始哈希。当初始位时 哈希耗尽,以下任一条件为真:
这里的关键是哈希位耗尽。
答案 3 :(得分:0)
碰撞的可能性非常低,通常只对大树造成问题。鉴于此,您最好只在叶子中的数组中存储碰撞并进行线性搜索(I do this in my C# HAMT)。