Ric*_*ral 3 c hashtable hash-collision quadratic-probing
我目前使用线性探测器的实现是使用线性探测,现在我想转向二次探测(以后再进行链接,也可能是双重哈希).我已经阅读了一些文章,教程,维基百科等...但我仍然不知道我应该做什么.
基本上,线性探测的步长为1,这很容易做到.当从哈希表中搜索,插入或删除元素时,我需要计算哈希值,为此我执行此操作:
index = hash_function(key) % table_size;
Run Code Online (Sandbox Code Playgroud)
然后,在搜索,插入或删除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 */);
Run Code Online (Sandbox Code Playgroud)
对于二次探测,我认为我需要做的是改变计算"索引"步长的方式,但这是我不明白应该怎么做的.我见过各种代码,而且所有代码都有所不同.
此外,我已经看到了一些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 }
Run Code Online (Sandbox Code Playgroud)
有两件事我没有得到......他们说二次探测通常是用来完成的c(i)=i^2.但是,在上面的代码中,它正在做更多的事情c(i)=(i^2-i)/2
我准备在我的代码上实现这个,但我只是这样做:
index = (index + (index^index)) % table_size;
Run Code Online (Sandbox Code Playgroud)
...并不是:
index = (index + (index^index - index)/2) % table_size;
Run Code Online (Sandbox Code Playgroud)
如果有的话,我会这样做:
index = (index + (index^index)/2) % table_size;
Run Code Online (Sandbox Code Playgroud)
...因为我已经看到其他代码示例潜水了两个.虽然我不明白为什么......
1)为什么减去这个步骤?
2)为什么要潜水2?
Mat*_*ery 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 */);
Run Code Online (Sandbox Code Playgroud)
而不是从原始索引中查看偏移0,1,2,3,4 ...,这将查看偏移0,1,3,6,10 ...(第i 个探针位于偏移(i*) (i + 1))/ 2,即它是二次的).
这可以保证打到哈希表中的每个位置(如果有的话,保证找到一个空桶),前提是表大小是2的幂.
这是一个证明草图:
(如果表格大小不是 2的幂,则在步骤10中分崩离.)