散列表类似于数组,可以把散列表的散列值看成数组的索引值,访问散列表和访问数组元素一样快速,他可以在常数时间内实现查找和插入操作。
由于无法通过散列值知道键的大小,因此散列表无法实现有序性操作。
散列函数
对于一个大小为M的散列表,散列函数能够把任意的数转换成【0,M-1】内的正整数,该正整数即为hash值。
散列表存在冲突,也就是两个不同的键可能有相同的hash值。
散列函数应该满足三个条件:
一致性:相等的键应当有相等的hash值,两个键相等表示调用equals返回的值相等
高效性:计算应当简便,有必要的话可以把hash值缓存起来,在调用hash函数时直接返回。
均匀性:所有键的hash值应当均匀地分布在【0,m-1】之间,如果不能满足这个条件,有可能产生很多冲突,从而导致散列表的性能下降。
除留余数法将整数散列到 [0, M-1] 之间,例如一个正整数 k,计算 k%M 既可得到一个 [0, M-1] 之间的 hash 值。注意 M 最好是一个素数,否则无法利用键包含的所有信息。例如 M 为 10k,那么只能利用键的后 k 位。
对于其它数,可以将其转换成整数的形式,然后利用除留余数法。例如对于浮点数,可以将其的二进制形式转换成整数。
对于多部分组合的类型,每个部分都需要计算 hash 值,这些 hash 值都具有同等重要的地位。为了达到这个目的,可以将该类型看成 R 进制的整数,每个部分都具有不同的权值。
例如,字符串的散列函数实现如下:
int hash = 0;
for (int i = 0; i < s.length(); i++)
hash = (R * hash + s.charAt(i)) % M;
Copy to clipboardErrorCopied
再比如,拥有多个成员的自定义类的哈希函数如下:
int hash = (((day * R + month) % M) * R + year) % M;
Copy to clipboardErrorCopied
R 通常取 31。
java中的hashcode(),实现了哈希函数,但