我目前使用线性探测器的实现正在使用线性探测,现在我想转向二次探测(以后再进行链接,也可能是双重哈希)。我已经阅读了一些文章,教程,维基百科等...但我仍然不知道我应该做什么。
线性探测基本上是1步,这很容易做到。当从哈希表中搜索,插入或删除元素时,我需要计算哈希值,为此我执行此操作:
index = hash_function(key) % table_size;
然后,在搜索,插入或删除I循环通过表时,直到找到一个空闲桶,如下所示:
do {
if(/* CHECK IF IT'S THE ELEMENT WE WANT */) {
// FOUND ELEMENT
return;
} else {
index = (index + 1) % table_size;
}
while(/* LOOP UNTIL IT'S NECESSARY */);
对于Quadratic Probing,我认为我需要做的是改变计算“索引”步长的方式,但这是我不明白应该怎么做的。我见过各种代码,而且所有代码都有所不同。
另外,我已经看到了一些Quadratic Probing的实现,其中哈希函数被改变为适应(但不是全部)。是真的需要改变还是我可以避免修改散列函数并仍然使用Quadratic Probing?
修改 在阅读了以下Eli Bendersky指出的所有内容后,我想我得到了一般的想法。以下是http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_hashtable.aspx代码的一部分:
15 for ( step = 1; table->table[h] != EMPTY; step++ ) {
16 if ( compare ( key, table->table[h] ) == 0 )
17 return 1;
18
19 /* Move forward by quadratically, wrap if necessary */
20 h = ( h + ( step * step - step ) / 2 ) % table->size;
21 }
有两件事我没有得到......他们说二次探测通常是使用c(i)=i^2
完成的。但是,在上面的代码中,它正在执行更像c(i)=(i^2-i)/2
我准备在我的代码上实现这个,但我只是这样做:
index = (index + (index^index)) % table_size;
......而不是:
index = (index + (index^index - index)/2) % table_size;
如果有的话,我会这样做:
index = (index + (index^index)/2) % table_size;
...因为我看过其他代码示例潜水两个。虽然我不明白为什么......
1)为什么要减去步骤?
2)为什么要潜水2?
答案 0 :(得分:11)
如果您的表格大小是2的幂,则有一种特别简单而优雅的方法来实现二次探测:
step = 1;
do {
if(/* CHECK IF IT'S THE ELEMENT WE WANT */) {
// FOUND ELEMENT
return;
} else {
index = (index + step) % table_size;
step++;
}
} while(/* LOOP UNTIL IT'S NECESSARY */);
不是从原始索引中查看偏移量0,1,2,3,4 ......而是查看偏移量0,1,3,6,10 ......(i th < / sup> probe位于偏移量(i *(i + 1))/ 2,即它是二次方。)
这可以保证打到哈希表中的每个位置(所以如果有的话,你可以保证找到一个空桶)提供表的大小是2的幂。
以下是证明的草图:
(如果表格大小不 2的幂,则在步骤10中分崩离析。)
答案 1 :(得分:4)
您不必修改二次探测的哈希函数。最简单的二次探测形式实际上只是将计算出的位置添加到计算位置而不是线性1,2,3。
有一个很好的资源here。以下是从那里开始的。当使用简单多项式c(i) = i^2
时,这是最简单的二次探测形式:
在更一般的情况下,公式为:
你可以选择你的常数。
但请记住,二次探测仅在某些情况下有用。正如Wikipedia entry所述:
二次探测提供了良好的记忆力 缓存,因为它保留了一些 参考地点;但是,线性的 探测具有更大的局部性, 因此,更好的缓存性能。 二次探测更好地避免了 可能发生的聚类问题 线性探测,虽然不是 免疫
编辑:与计算机科学中的许多事物一样,二次探测的精确常数和多项式是启发式的。是的,最简单的形式是i^2
,但您可以选择任何其他多项式。维基百科给出了h(k,i) = (h(k) + i + i^2)(mod m)
的示例。
因此,很难回答你的“为什么”的问题。这里唯一的“为什么”是为什么你需要二次探测?遇到其他形式的探测和获取群集表的问题?或者只是作业或自学?
请记住,到目前为止,哈希表最常见的冲突解决方法是链接或线性探测。二次探测是一种适用于特殊情况的启发式选项,除非您知道自己做得很好,否则我不建议使用它。