--- title: java散列知识点总结 date: 2017-02-18 19:19:01 category: notes tags: - Algorithms keywords: - hash - 散列 - 哈希 - java --- java 的根类 `Object` 具有 `hashcode` 方法。当 `equal` 方法被重写时也应当重写 `hashcode` 方法。 ## 基本数据类型的散列码 * `byte` `short` `int` `char` 类型的搜索键将会转换为 `int`。 * `float` 类型的搜索键使用 `Float.floatToIntBits(key)` 作为散列码。 * `long` 类型的搜索键会进行折叠操作,如下: ```java iny hashCode = (int) (key ^ (key >> 32)); ``` * `double` 类型的搜索键会使用 `Double.doubleToLongBits(key)` 方法转换为 `long` 类型然后再进行折叠。 ## 字符串类型的散列码 对于字符串一般使用多项式散列码进行计算, ~~这里放个公式的图~~ b的较好取值为31,33,37,39,41。在 java String 类中 `b` 取31。 ```java 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。