---
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。
