我用Java编写HashMap的实现。我使用开放寻址来解决冲突。为了更好的密钥分发,我想为密钥的int
哈希码使用一个很好的哈希函数。我不知道什么哈希函数对它更好?
public int getIndex(K key) { return hash(key.hashCode()) % capacity; }
我需要一个哈希函数来获取密钥的哈希码。
答案 0 :(得分:3)
任何散布您希望均匀接收的值的散列都是一个很好的散列函数。
您的目标是最大限度地提高性能(在保持正确性的同时最大限度地提高性能)。主要关注的是最小化铲斗碰撞。这意味着理想的哈希值是根据您的输入数据量身定制的 - 如果您知道要接收的内容,则可以选择产生最少数量冲突的哈希值,甚至可以选择缓存最佳访问模式。
然而,这通常不是一个现实的选择,因此您只需选择一个输出无偏和不可预测的散列(一个行为类似于伪随机数生成器,但确定性)。一些这样的函数是“杂音”哈希家族。
答案 1 :(得分:1)
使用% capacity
的主要问题是它可以返回负值和正值。
HashMap使用2的幂并使用以下方法
来避免此问题 public int getIndex(K key) { return hash(key.hashCode()) & (capacity-1); }
如果容量不是2的幂,你可以忽略高位(通常不是那么随机)
public int getIndex(K key) { return (hash(key.hashCode()) & 0x7FFFFFFF) % capacity; }
实际使用的哈希函数很重要。 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);
}
我会用这个,除非你有充分的理由不这样做。例如。出于安全原因,如果您有可能遭受拒绝服务攻击的服务,您将需要使用不同的哈希来避免恶意用户将您的HashMap转换为LinkedList。不幸的是,您仍然必须使用不同的hashCode(),并且您可以使用基础哈希代码创建一个很长的字符串列表,因此稍后对其进行更改也会更晚。
这是一个字符串列表,其中所有字符串的hashCode()都为0,hash()函数无法做到这一点。