题干太长了,这次不写题干了,主要说说散列表,又叫哈希表(hash table)
散列表是一种存储数据的方法,通过散列表,可以实现直接用关键字(key)访问数据所在位置。具体实现方法为使用散列函数(哈希函数)H(key),对每个关键字,都可以计算出一个地址。显然,不同的关键字可能有同一个地址,造成地址冲突,有解决这些地址冲突的方法。
H(key)=address
哈希函数有很多种构造方法,常用的有除留余数法等,除留余数法如下,memory_size为分配的存储区域的容量。
H(key%memory_size)=address
其他方法也能将关键字转成对应地址。
如果两个不同键值计算出了相同的地址,就叫做发生了冲突,这些发生碰撞的不同关键字称为同义词,例如除留余数法,若memory_size=5,那么关键字6和11计算出的地址是相同的。
产生冲突,就需要就解决冲突的方法。解决冲突有两大类方法,一是开放定址法,二是链接法。
- 开放定址法:定义很抽象,大意就是采用某种规则,发生冲突后,重新计算地址进行试探。设第i次冲突时下一个试探地址是Hi,则数学公式是Hi=(H(key)+di)%m。我们的目的是确定重新计算的规则,也就是确定di的取值,来不停地计算试探地址,直到找到不冲突的地址或者超过试探次数限制。常用的开放定址法有常用的开放定址法有平方探测法等。
平方探测法:di=0,12,-12,22,-22,···,k2,-k2,k<=m/2.依次试探上述取值,直到找到空闲地址或者试探超过m+1次。
本题中就要使用平方探测法。
#include <bits/stdc++.h>
#define N 100000
using namespace std;
bool is_Prime(int n) {
if (n==1||n==0) return false;
for (int i=2;i*i<=n;i++)
if (n%i==0) return false;
return true;
}
int ha[N];
int main() {
int s,n,m,ans=0;
scanf("%d%d%d",&s,&n,&m);
while (!is_Prime(s)) s++;
for (int i=0;i<n;i++) {
int flag=0,t=0;
scanf("%d",&t);
for (int j=0;j<=s;j++) {
int key=(t+j*j)%s;
if (ha[key]==0) {
ha[key]=t;
flag=1;
break;
}
}
if (!flag) printf("%d cannot be inserted.\n",t);
}
for (int i=0;i<m;i++) {
int t=0;
scanf("%d",&t);
for (int j=0;j<=s;j++) {
ans++;
int tk=(t+j*j)%s;
if (ha[tk]==t||ha[tk]==0) break;
}
}
printf("%.1f\n",1.0*ans/m);
return 0;
}