位模式的哪些属性会导致冲突?

时间:2015-06-04 18:34:16

标签: java algorithm hash hashmap hash-collision

我正在阅读Java的随机化哈希键here的方法 显然,我们的想法是确保较低位是“随机”以帮助分发,但我想更多地了解这一点。
因此,如果我们有一个大小为10的表,那么数字0,10,20,30,40等都落在桶0中,数字1,11,21,31等落在桶1等中(使用模10)。登记/> 因此,改变位模式,你可以使它们进入不同的桶而不是全部进入桶0 但是我不清楚的是它是什么属性使得低阶位影响这一点,我们需要将它们随机化。 所以我们有:

0000 0000 (0)  
0000 1010 (10)  
0001 0100 (20) 
0001 1110 (30)  
0010 1000 (40) 

低位比特的规律性是什么使它们被放置在同一个插槽中? 也许我对以下内容感到困惑?我的理解是,低阶位的一些规律性会导致冲突,我们会尝试随机化比特来补偿

2 个答案:

答案 0 :(得分:2)

一些散列函数在随机化低阶位方面做得非常糟糕。

一个经典案例是使用硬件地址作为对象引用的哈希值(C中的“指针”),否则这将是廉价获取对象id的唯一编号的合理方法。如果哈希表的桶数是素数,这将正常工作,但对于桶的数量始终为2的幂的哈希实现,所有哈希值可被8整除的事实意味着大多数桶都是空的。 / p>

这是一个极端的情况,但是任何时候要散列的数据都不是均匀分布的并且散列函数倾向于保留低阶位,你会在存储桶分配中发现一些偏差。

答案 1 :(得分:2)

Java的HashMap使用的哈希表大小为2的幂。如果您像往常一样使用余数/模运算作为压缩函数,则最终将哈希码的最低位作为存储区索引。如果哈希码恰好是幂2的倍数,则一些最低位将始终为零,并且最终使用可用桶的一小部分。

具体示例:假设您有32个桶,并且哈希码是8的倍数。该表仅使用代码的5个最低有效位,其中3个总是0.因此只有2位确定桶,并且你只使用32个桶中的4个:

XXXXXX00000 -> bucket 0
XXXXXX01000 -> bucket 8
XXXXXX10000 -> bucket 16
XXXXXX11000 -> bucket 24

幸运的是,Java中的东西并不是很糟糕,因为HashMap并不仅仅使用哈希代码的最低位:它会对位进行加扰,这样就不会很容易意外地产生错误的场景。这是OpenJDK的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);
}