java散列知识点总结
java 的根类 Object
具有 hashcode
方法。当 equal
方法被重写时也应当重写 hashcode
方法。
基本数据类型的散列码
byte
short
int
char
类型的搜索键将会转换为int
。float
类型的搜索键使用Float.floatToIntBits(key)
作为散列码。long
类型的搜索键会进行折叠操作,如下:
iny hashCode = (int) (key ^ (key >> 32));
double
类型的搜索键会使用Double.doubleToLongBits(key)
方法转换为long
类型然后再进行折叠。
字符串类型的散列码
对于字符串一般使用多项式散列码进行计算,
这里放个公式的图
b的较好取值为31,33,37,39,41。在 java String 类中 b
取31。
public static int hash(String key, int tableSize)
{
int hashVal = 0;
for (int i = 0; i < key.length(); i++)
hashVal = 37*hashVal + key.charAt(i);
hashVal %= tableSize;
if (hashVal < 0)
hashVal += tableSize;
return hashVal;
}
压缩散列码
由于散列码可能是很大的正数,通常应该对其进行压缩以防止超出索引的范围。若索引范围为 0 ~ n - 1
,通常的做法是 h(hashCode) = hashCode % N
,选择N为大于2的素数。
java.util.HashMap
的实现中,将N设置为2的幂值,这样可以使用位运算代替上述的取模:h(hashCode) = hashCode & (N - 1)
,两者是完全等价的。
处理冲突
开放地址法
开放地址法是在冲突发生时,在散列表中找到一个开放位置的过程。
- 线性探测,存在成簇问题
- 二次探测,存在二次成簇问题,并且不能保证一个开放的单元总是可以被找到。
- 再哈希法
链地址法
链地址法是将具有同样索引的条目放在同一位置,每个位置使用一个桶(ArrayList or LinkedList)来放置多个条目。
装填因子
装填因子衡量一个散列表有多满。lamda = n / N
。对于开放地址法,装填因子介于 0 ~ 1,对于链地址法,装填因子可能为任意值。通常开放地址法需要将装填因子维持在0.5以下,而链地址法为0.9以下。java.util.HashMap
采用了阈值0.75。