我正在尝试使用Double Hashing将String键散列到哈希表中。我做了类似的事情:
protected int getIndex(String key) {
int itr = 0,
size = this.values.length,
index1,
index2,
index = 0;
do {
// do double hashing to get index for curr [itr] (iteration)
index1 = Math.abs(key.hashCode()) % size;
index2 = size - ((key + key + "#!@").hashCode() % size); # trying very hard to eliminate clash, but still fails ... TA and AT gets index 2 when size = 5
index = (index1 + (itr * index2)) % size;
// if itr > set threshold, exit
itr++;
if (itr > 200) {
index = -1;
break;
}
// once index found, exit loop
} while (index > 0 && this.keys[index] != null && !this.keys[index].equals(key));
return index;
}
主要部分是do
之后的前3行。我可以说如果我使用Double Hashing,它应该消除碰撞的概率吗? size
是哈希表的唯一键的总可能值
答案 0 :(得分:2)
所以我看到这里发生了两件事
乍一看,看起来这两种方法都是减少哈希冲突的好方法。然而,经过仔细检查,这两者都会陷入真正的算法麻烦。
合并两个哈希
散列算法被设计为在整数范围内相当好地分布。就像将两个随机数加在一起并没有给你任何更多的randomer一样,将两个哈希加在一起并不会让你获得更多的分布。事实上,将两个符号分布一起添加将总是给你一些不均匀分布的东西。因此,任何一种使用相同底层算法的双重哈希策略都比单个哈希策略更差。
尝试新地点
尝试在第一个碰撞时尝试新哈希的算法很有吸引力。但是,这会导致算法的检索部分出现问题。当你在哈希中放入一些东西时,它会碰到另一个位置。然后,当你去检索值时,它不在那里。更糟糕的是,你是否发现它取决于第一个元素是否仍然存在。如果它被删除了,那么就无法判断你正在寻找的项目是否还在继续,或者它是否就在那里。最终,一个.contains测试必须经过所有200次迭代才能确定它所寻找的哈希值不存在。
最好的解决方案是使用Java提供的开箱即用哈希。如果你遇到很多冲突,最好在哈希中使用较低的加载因子。这会增加存储桶的数量,并导致冲突的可能性降低。