Algorithm 我们可以使用1表实现布谷鸟哈希吗?

Algorithm 我们可以使用1表实现布谷鸟哈希吗?,algorithm,optimization,data-structures,hash,hashtable,Algorithm,Optimization,Data Structures,Hash,Hashtable,我找到了大约个,看起来不错。 但我发现的大多数示例代码都是使用两个表实现的。 在我看来,这似乎是错误的,因为这两个表可能位于不同的内存页中,我们有获取随机地址的开销,并且没有实际的局部性。 不能使用1个数组而不是2个数组吗? 是否可能无法检测某个元素何时已被踢出2次,是否需要调整大小?好吧,所有形式的哈希都会在缓存中被杀死 无论如何,您可以轻松地将这两个表合并到一个表中。但是,如何判断您使用的是第一个散列函数还是第二个散列函数呢?选项是将其作为元数据添加到每个bucket中,或者通过运行第一个散

我找到了大约个,看起来不错。
但我发现的大多数示例代码都是使用两个表实现的。
在我看来,这似乎是错误的,因为这两个表可能位于不同的内存页中,我们有获取随机地址的开销,并且没有实际的局部性。
不能使用1个数组而不是2个数组吗?

是否可能无法检测某个元素何时已被踢出2次,是否需要调整大小?

好吧,所有形式的哈希都会在缓存中被杀死

无论如何,您可以轻松地将这两个表合并到一个表中。但是,如何判断您使用的是第一个散列函数还是第二个散列函数呢?选项是将其作为元数据添加到每个bucket中,或者通过运行第一个散列函数,查看是否获得当前位置,并仅在您位于第一个位置时运行第二个散列函数来确定它。这要么需要额外的空间,要么运行更多的散列函数


将表拆分为2可以更有效地解决该问题。从统计上讲,无论表是否已拆分,都需要相同数量的存储桶来存储相同数量的内容。因此,您的整个哈希表变得更小。

回答注释中的困惑:不,这不是特定于语言的。如果您正在考虑内存的局部性,并且希望确保两个表是接近的,那么单次分配是最好的选择(不管您如何分配)。在java中,这可能如下所示:

class-two表{
私有静态最终整数大小表第一个=11,大小表第二个=29;
公共双表(){
m_buffer=newint[SIZE_TABLE_FIRST+SIZE_TABLE_SECOND];
}
/考虑类似的设置…
公共int getFirst(int键){
返回m_buffer[toIndex(hashFirst(键),SIZE_TABLE_FIRST,0)];
}
公共整数getSecond(整数键){
返回m_缓冲区[toIndex(哈希秒(键),大小表秒,大小表首)];
}
私有静态int-toIndex(int散列、int-mod、int-offset){
返回哈希%mod+偏移量;
}
私有静态int hashFirst(int key){return…;}
私有静态int hashSecond(int key){return…;}
专用最终int[]m_缓冲区;
}
但是,如果这比访问两个单独的数组更好,则取决于您的JVM:只需考虑JIT能够动态地将两个较小的分配合并为一个较大的分配,而无需执行任何索引魔术。

是的


你可以在spoj上检查这个问题,我们需要使用一个哈希表和两个哈希函数来解决这个问题。

你完全可以使用一个哈希表来处理布谷鸟哈希表;也就是说,每个对象的两个位置只是单个哈希表中的位置

唯一需要解决的小问题是,如何在布谷鸟逐出循环期间决定将两个位置中的哪一个用于逐出键。当然,如果第一个位置与实际位置相同,您可以尝试一个位置并使用另一个位置。应该可以使用SIMD并行计算这两个哈希,因此此策略的成本可能很小

但是,如果您想保证在布谷鸟循环期间进行单个哈希计算,有一个简单的解决方案:使用
H0(k)
H1(k)
作为两个位置,而不是使用
H0(k)
H0(k)xorH1(k)
。(如果
H1
独立于
H0
,那么
H0xorH1
也是独立的,所以异或不会影响散列值的分布。)通过此修改,您可以通过将当前位置与
H1(k)
异或,始终找到
k
的“其他位置”,因此,循环中只需要一次散列计算


虽然这允许您使用单个哈希表,甚至可以简化代码,但没有很多证据表明它改进了算法的操作。在我有限的测试中,它似乎将循环迭代次数增加了40-50%。(尽管需要强调的是,在绝大多数情况下,可以在不进入循环的情况下将新键插入表中,因此在实际执行时间内,循环数的增加几乎不明显。)

您可以在同一内存块中分配两个表,即一次分配,要确保空间位置,请分配一个表,然后将其切分为两部分。还要注意,在当今的系统上,一级缓存的大小顺序为几KBs(例如查找当前的英特尔微体系结构)这样就有了存储几页内存的空间——必须索引到少量的页面应该不是问题either@BeyelerStudios:这是一个特定于语言的问题吗?例如,我对Java感兴趣,但您不能这样做this@harold:我在想,如果使用1,可能无法检测到这是元素的第二次逐出表。两个哈希函数是否有可能因数组的某些元素和大小而发生冲突,因此实际上不使用两个表是不可避免的?
所有形式的哈希都是在缓存上进行的。
据我所知,open addressing没有您认为的问题mention@Jim在插入时,插入始终有可能创建一个循环,您必须使用两个新的哈希函数重建表。不管你用一张桌子还是两张桌子,这都是事实。至于散列杀死缓存,我说的是全部,我的意思是全部。第一步是计算散列函数并跳转到内存块中的伪随机位置。如果该块大于缓存,则可能会破坏缓存。具体例子。在许多用例中,一个数据量超过RAM的BTree在每次查找一个磁盘寻道下的平均值非常显著。同样大小的散列总是在寻找。@b我可以反驳这句话
所有形式的散列都是在缓存中被谋杀的
。1) 根据帕累托原理,一小部分条目可能构成访问的主要部分,即hot和sit