问题描述
请实现一个能执行以下命令的简易字典
insert str: 向字典中添加字符串str
find srt: 当前字典中包含str时输出yes,不包含时输出no
输入 第1行中输入命令数n。随后n行按顺序输入n个命令。命令格式如上。
输出 对于各find命令输出yes或no,每个输出占一行。
限制 输入的字符串仅由“A”,“C”,“G”, “T”四种字母构成。(脱氧核糖核酸)
1≤字符串长度≤12
n≤1000000
输入示例
6
insert AAA
insert AAA
find AAA
find CCC
insert CCC
find CCC
输出示例
yes
no
yes
讲解
散列法是一种搜索算法,它可以根据各元素的值来确定存储位置,然后将位置保管在散列表中,从而实现数据的高效搜索。其中散列表是一种数据结构,能对包含关键字的数据集合高效地执行动态插入、搜索、删除操作。
散列表由容纳m个元素的数组T,以及根据数据关键字决定下标的函数共同组成。也就是说,我们要将数据的关键字输入该函数,由该函数决定数据在数组中的位置。散列表大概可以通过以下方法实现
insert(data)
T[h(data.key)] = data
search(data)
return T[h(data.key)]
这里我们假设散列函数的输入值data.key为整数。请注意,当关键字为字符串等其他类型时,需要借助某些手段将其转换为相应的整数。
这里的h(k)时根据k值求数组T下标的函数,称为散列函数。另外,该函数的返回值称为散列值。散列函数求出的散列值范围在0到m - 1之间(m为数组T的长度)。为满足这一条件,函数内需要用取余运算,保证输出值为0到m - 1之间的整数。
比如h(k)=k mod m
这就是一种散列函数。不过,如果单有这一个运算,会发生不同key对应同一散列值的情况,即出现"冲突"。
开放地址法是解决这类冲突的常用手段之一。这里是双散列结构中使用的开放地址法如下,在双散列结构中一旦发生冲突,程序会调用第二个散列函数来求散列值
H(k)=h(k,i)=(h1(k)+i*h2(k)) mod m
散列函数h(k,i)拥有关键字k和整数i两个参数。这里的i是发生冲突后计算下一个散列值次数。也就是说,只要散列函数H(k)起了冲突,就会依次调用h(k,0), h(k,1), h(k,2)…直到不发生冲突为止,然后返回h(k,i)的值作为散列值。
要注意的是,因为下标每次移动h(k)个位置,所以必须保证T的长度m与h2(k)互质,否则会出现无法生成下标的情况。这种时候,我们可以特意让m为质数,然后取一个小于m的值作为h2(k),从而避免上述情况的发生
AC代码如下
#include<stdio.h>
#include<string.h>
#define M 1046527
#define NIL (-1)
#define L 14
char H[M][L];
//将字符转换为数值
int getChar(char ch){
if(ch == 'A') return 1;
else if(ch == 'C') return 2;
else if(ch == 'G') return 3;
else if(ch == 'T') return 4;
else return 0;
}
//将字符串转换为数值并生成key
long long getKey(char str[]){
long long sum = 0, p = 1, i;
for(i = 0; i < strlen(str); i++){
sum += p*(getChar(str[i]));
p *= 5;
}
return sum;
}
int h1(int key){return key % M;}
int h2(int key){return 1 + (key % (M - 1));}
int find(char str[]){
long long key, i, h;
key = getKey(str);//将字符串转换为数值
for(i = 0;;i++){
h = (h1(key) + i * h2(key)) % M;
if(strcmp(H[h], str) == 0) return 1;
else if(strlen(H[h]) == 0) return 0;
}
return 0;
}
int insert(char str[]) {
long long key, i, h;
key = getKey(str);//将字符串转换为数值
for(i = 0; ; i++){
h = (h1(key) + i * h2(key)) % M;
if(strcmp(H[h], str) == 0) return 1;
else if(strlen(H[h]) == 0){
strcpy(H[h], str);
return 0;
}
}
}
int main(){
int i, n, h;
char str[L], com[9];
for(i = 0; i < M; i++) H[i][0] = '\0';
scanf("%d", &n);
for(i = 0; i < n; i++){
scanf("%s %s", com, str);//使用速度更快的输入函数scanf
if(com[0] == 'i') {
insert(str);
} else {
if(find(str) ){
printf("yes\n");
}else {
printf("no\n");
}
}
}
return 0;
}