Algorithm hashmap中的简单hashcode误解?

Algorithm hashmap中的简单hashcode误解?,algorithm,hashmap,hash-code-uniqueness,Algorithm,Hashmap,Hash Code Uniqueness,我正在实现我自己的专用hashmap,它具有泛型值类型,但键的类型总是long。在这里和那里,我看到有人建议我用一个素数乘以key,然后用桶数得到模: int bucket = (key * prime) % numOfBuckets; 我不明白为什么?在我看来,它的分布与simple完全相同: int bucket = key % numOfBuckets; 例如,如果numofbucket是8,那么使用第二个“算法”,我们可以得到像{0,1,2,3,4,5,6,7}这样的bucket,对

我正在实现我自己的专用hashmap,它具有泛型值类型,但键的类型总是long。在这里和那里,我看到有人建议我用一个素数乘以key,然后用桶数得到模:

int bucket = (key * prime) % numOfBuckets;
我不明白为什么?在我看来,它的分布与simple完全相同:

int bucket = key % numOfBuckets;
例如,如果numofbucket是8,那么使用第二个“算法”,我们可以得到像{0,1,2,3,4,5,6,7}这样的bucket,对于key=0到无穷大重复。在相同密钥的第一个算法中,我们得到的bucket{0、3、6、1、4、7、2、5}(或类似的)也在重复。基本上,我们有相同的问题,比如使用身份散列

基本上,在这两种情况下,关键点都会发生碰撞:

key = x + k*numOfBuckets (for k = 1 to infinity; and x = key % numOfBuckets)

因为当我们通过num得到模时,我们总是得到x。那么,第一个算法的处理方法是什么,有人能告诉我吗?

如果
numobkets
是二的幂,并且
prime
是奇数(这似乎是预期的用例),那么我们就有
gcd(numobkets,prime)==1
。这反过来意味着有一个数
,使得
逆*numobeckets=1(mod numobeckets)
,因此乘法是一个双射运算,只需将存储桶围绕一位进行洗牌。那当然没用,所以你的结论是正确的

或者更直观地说:在乘法中,信息只从最低位流向最高位,从不反向流动。因此,桶索引在没有乘法的情况下不会依赖的任何位仍然会在乘法中被丢弃

其他一些技术也有帮助,例如Java的HashMap使用以下技术:

/**
 * Applies a supplemental hash function to a given hashCode, which
 * defends against poor quality hash functions.  This is critical
 * because HashMap uses power-of-two length hash tables, that
 * otherwise encounter collisions for hashCodes that do not differ
 * in lower bits. Note: Null keys always map to hash 0, thus index 0.
 */
static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

另一个有效的方法是乘以某个大常数,然后使用结果的高位(其中包含低位的混合,因此键的所有位都可以这样使用)。

谢谢,前两段是我想要的答案。还有一个问题,一些鼓吹用素数乘法的人说,这是克努特的《计算机编程的艺术》中的算法,他用2654435761乘法。Knuth的散列算法是否有不同的用例,或者他们完全误解了算法?@harold在jdk-8中重新散列的内部已经改变;这是前16位和后16位之间的简单异或bits@vladaKnuth的乘法散列必须右移以减少它,而不是AND或长度的缩减模。这是一件经常被遗忘的事情。你必须在这里质疑另一件事,关于
%
。hashcodes可以是负数,
%
将返回负数bucket。。。至少在java中是这样