散列:将元素通过一个函数转化为整数,使得该整数能够唯一的代表这个元素。
简单的说明一下散列的必要性:假如给定N个整数,再给定M个整数,N,M<=10^5。求M个数是否在N个数中出现过。
最先的思路是遍历N个数,一个个找,随后我们会想到,何不在输入是创建一个数组bool类型a[X],用来表示X元素是否在N个数中出现过,即:
for(int i = 0;i < N;i++)
{
cin >> X;
a[x]=true;
}
这样时间复杂度降低为O(1),但是当N的数值达到10^9时,或者输入的是N个字符类型的值时,上面这种方法便不能再使用,这时我们就会用到散列(hash)。将该元素通过以后、个函数转化为整数。为了描述方便,假设转化前元素为X,转化后为Y,散列函数记为H()。
1.当X为整数时,常用的转化方法有直接定址法,平方取中法,除留余数法。
A.直接定址法即为恒等变换,即H(X)=X 或 H(X)=a*X+b,也就是最开始介绍的建立一个bool类型数组的方法。
B.平方取中法:指取X的平方的中间若干位作为H(X)的值。
C.除数留余法:把X除以一个数mod得到的余数作为H(X)值的方法。该方法有个弊端即不同的X值除以mod后可能得到相等的结果。解决该问题的方法有:
1.线性探查法:当H(X)的值被占用时,新的H(X‘)取H(X)+1,仍被占用就+2,依次类推。可见该方法容易使得H(X)扎堆。
2.平方探查法:当H(X)的值被占用时,新的H(X‘)取H(X)+1^2 , H(X)-1^2 , H(X)-2^2 , H(X)+2^2......
3.链地址法:当H(X)的值被占用时,就在H(X)后面加一个链表来存储新的H(X)的值。
2.当X不是整数时,通常利用字符串Hash来解决,字符串Hash是指将字符串S映射为一个整数。
该方法即利用字符对应的ASCII值,转化成整数。这里不再给出代码。