我当前的哈希表实现是使用线性探测,现在我想转向二次探测(后来转向链接,也许还有双重哈希)。我读过一些文章、教程、维基百科等......但我仍然不知道我到底应该做什么。
基本上,线性探测的步长为 1,这很容易做到。当从哈希表中搜索、插入或删除元素时,我需要计算哈希值,为此我这样做:
index = hash_function(key) % table_size;
然后,在搜索、插入或删除时,我循环遍历表,直到找到一个空闲的存储桶,如下所示:
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 */);
至于二次探测,我认为我需要做的是改变“索引”步长的计算方式,但这就是我不明白应该如何做。我看过各种代码,它们都有些不同。
另外,我已经看到了二次探测的一些实现,其中哈希函数被更改以适应这种情况(但不是全部)。是否真的需要进行这种更改,或者我可以避免修改哈希函数并仍然使用二次探测吗?
EDIT:在阅读了 Eli Bendersky 下面指出的所有内容后,我想我已经有了总体想法。这是代码的一部分http://eternallyconfuzzled.com/tuts/datastructs/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 倍?