我想知道我们是否实现了自己的hashmap,它不使用两个幂的长度哈希表(初始容量和每当我们重新调整大小),那么在这种情况下我们可以只使用对象的哈希码并修改总大小直接而不是使用哈希函数来散列对象的哈希码?
例如
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
// int hash = hash(key.hashCode()); original way
//can we just use the key's hashcode if our table length is not power-of-two ?
int hash = key.hashCode();
int i = indexFor(hash, table.length);
...
...
}
答案 0 :(得分:3)
假设我们在谈论OpenJDK 7,额外的hash
用于刺激雪崩;它是mixing function。之所以使用它是因为从散列到存储桶的映射函数,因为容量为2的幂,只是按位&
(因为a % b
等同于a & (b - 1)
iff b
是2)的力量;这意味着低位是唯一重要的位,因此通过应用这个混合步骤,它可以帮助防止较差的哈希值。
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);
}
如果您想使用不是2的大小,则不需要上述 。
实际上更改从哈希到桶的映射(通常依赖于容量为2的幂)将要求您查看indexFor
:
static int indexFor(int h, int length) {
return h & (length-1);
}
您可以在此处使用(h & 0x7fffffff) % length
。
答案 1 :(得分:1)
您可以将mod函数视为哈希函数的简单形式。它将大范围的数据映射到较小的空间。假设原始哈希码设计得很好,我认为没有理由不能使用mod将哈希码转换为你正在使用的表的大小。
如果您的原始哈希函数没有很好地实现,例如总是返回一个偶数,你只需要一个mod函数就可以创建很多碰撞。
答案 2 :(得分:1)
这是事实,你可以选择伪素数。
注意:indexFor需要使用%
来补偿符号而不是简单的&
,这实际上可以使查找更慢。
indexFor = (h & Integer.MAX_VALUE) % length
// or
indexFor = Math.abs(h % length)