题意:哈希映射,利用平方探测法解决冲突,并计算平均查找时间。
思路:首先,需掌握什么是平方探测法(Quadratic probing)。所谓平方探测法,即当H(key)发生冲突时,让key按key+1^2,key-1^2,key+2^2,key-2^2......的顺序进行调整,而题目中说明只需要往正方向解决冲突,即解决冲突的函数为H(key)=(key+d^2)%TSize,d=0,1,2,...TSize-1,其中TSize为哈希表的表长。其次,需掌握如何计算平均查找时间,所谓平均查找时间,就是每个查询值的比较次数之和除以查询个数,下面以样例进行说明,下表为建立好的哈希表。
hashtable[i] | 10 | 6 | 11 | 4 | |
i | 0 | 1 | 2 | 3 | 4 |
(1).当查询值key=11时,H(11)=11%5=1,发现hashtable[1]≠11(第1次比较),即发生冲突,继续查找;
H(11)=(11+1^2)%5=2,此时hashtable[2]==11(第2次比较),查找成功,共查找了2次。
(2).当查询值key=4时,H(4)=4%5=4,发现hashtable[4]==4(第1次比较),查找成功,共查找了1次。
(3).当查询值key=15时,H(15)=15%5=0,发现hashtable[0]≠15(第1次比较),即发生冲突,继续查找;
H(15)=(15+1^2)%5=1,此时hashtable[1]≠15(第2次比较),发生冲突,继续查找;
H(15)=(15+2^2)%5=4,此时hashtable[4]≠15(第3次比较),发生冲突,继续查找;
H(15)=(15+3^2)%5=4,此时hashtable[4]≠15(第4次比较),发生冲突,继续查找;
H(15)=(15+4^2)%5=1,此时hashtable[1]≠15(第5次比较),还是发生冲突,此时正向偏移d已经等于TSize-1,故不用再继续查询了,说明key=15查询失败,它总共查找了5次。——但是,若key值在d从0~TSize-1进行枚举后仍然无法解决冲突,PAT里在这种情况下要多加1次,也就是认为key=15总共比较了6次!!!还没搞明白!!!
(4).当查询值key=2时,H(2)=2%5=2,发现hashtable[2]≠2(第1次比较),即发生冲突,继续查找;
H(2)=(2+1^2)%5=2,此时hashtable[2]为空(第2次比较),说明这个值不在表中,故查找结束,共查找了2次。
因此,平均查找时间为(2+1+6+2)/4≈2.8
代码:
#include <cstdio> #include <cmath> #include <cstring> const int N=10005; int hashtable[N]={0}; bool isPrime(int n) { if(n<=1) return false; int sqr=(int)sqrt(n); for(int i=2;i<=sqr;i++) if(n%i==0) return false; return true; } int main() { int MSize,n,queryCnt,key; scanf("%d%d%d",&MSize,&n,&queryCnt); while(!isPrime(MSize)) MSize++; while(n--){ scanf("%d",&key); int d=0; for(;d<MSize;d++){ int p=(key+d*d)%MSize; if(hashtable[p]==0){ hashtable[p]=key; break; } } if(d==MSize) printf("%d cannot be inserted.\n",key); } int tot=0;//总的查询次数 int tmp=queryCnt; while(tmp--){ scanf("%d",&key); int d=0; int cnt=0;//key值的查询次数 for(;d<MSize;d++){ int p=(key+d*d)%MSize; cnt++; if(hashtable[p]==0 || hashtable[p]==key) break;//遇到空位置或找到对应的值 } if(d==MSize) cnt++;//注意特殊情况,对应上述查询key=15 tot+=cnt; } printf("%.1f",1.0*tot/queryCnt); return 0; }