前言
在散列(hashing)中,元素储存在一个散列表(hash table)内,它们在散列表的位置由散列函数(hashing function)确定, 每个位置可以称为桶(bucket)或者单元(cell).
散列函数
java.lang.Object中定义了public native int hashCode()方法,根据对象的内存地址返回了一个整数值,所有的java对象都可以被散列. 从Object派生而来的类通常会重写hashcode方法,以提供自己的hashcode版本.
最为典型的就是java.lang.String的hashcode实现
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
参考注释,hash计算公式可以计为s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],
n为字符串长度,s[]即为String源码中其内部维护的char类型的数组val[],
推导如下:如果字符串长度 n = 3
i = 0 -> h = 31 * 0 + val[0] = val[0];
i = 1 -> h = 31 * (31 * 0 + val[0]) + val[1] = 31 * val[0] + val[1];
i = 2 -> h = 31 * (31 * (31 * 0 + val[0]) + val[1]) + val[2] = 31^2 * val[0] +31 * val[1] + val[2];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
如有兴趣,请参考String hashCode()为何选用31作为乘子
直接寻址法
以数据元素关键字本身或它的线性函数作为它的hash地址,即Hk = k 或者 Hk = a*k+b(a,b为常数)
例1: 统计XX市年龄分布表,记录从1岁到110岁的人口数目,以年龄为关键字,hash函数取关键字本身.
地址 | A1 | A2 | …… | A100 | …… | A109 | A110 |
---|---|---|---|---|---|---|---|
年龄 | 1 | 2 | …… | 100 | …… | 109 | 110 |
人数 | 200 | 500 | …… | 30 | …… | 1 | 0 |
当要查询某一年龄对应的人数,直接查询对应的地址.如需查找100岁的人,读出100项的值.
实际应用当中,关键字很少连续,此方法生成的hash表可能造成空间的大量浪费
适用范围 地址集合大小==关键字集合大小
折叠法(folding method)
关键字被分割成多个部分,然后再组合或叠加到一起以创建散列表的索引.
实现方式: 将关键字按照所需的索引长度切分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位).
平移折叠法: 将分割后的每一部分的最低位对齐相加
边界折叠法: 从一端向另一端沿分割界来回折叠,然后对齐相加
适用范围 关键字位数较多,而且关键字中每一位上数字分布大致均匀
余数法
平方取中法
基数转换法
数字分析法
长度相关法
完美散列函数
散列冲突
两个元素或者关键字映射到散列表相同的位置的情况称为散列冲突