这道题目是哈希查找的典型题目,先打表后查找,思路非常简单。但是输入中存在许多问题。我开始用的是hash写的,超时了,下面是我哈希的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 999983
struct Node{
char english[12];
char foreign[12];
struct Node *next;
}node[Max];
bool flag[Max];
char source[12];
char target[12];
int slen,tlen;
void Hash(bool trag){
int key=0;
for(int i=0;i<tlen;i++)
key+=(target[i]-'0');
int pos=key%Max;
if(!trag){
if(!flag[pos]){
flag[pos]=1;
strcpy(node[pos].english,source);
strcpy(node[pos].foreign,target);
node[pos].next=NULL;
}
else{
struct Node *index=(struct Node*)malloc(sizeof(struct Node));
strcpy(index->english,source);
strcpy(index->foreign,target);
index->next=node[pos].next;
node[pos].next=index;
}
}
else{
if(!flag[pos])
printf("eh\n");
else{
struct Node *index=&node[pos];
while(index!=NULL){
if(strcmp(index->foreign,target)==0){
printf("%s\n",index->english);
return ;
}
index=index->next;
}
printf("eh\n");
}
}
}
int main(){
memset(flag,0,sizeof(flag));
char str;
int slen,tlen;
bool sym;
while(true){
str=getchar();
if(str=='\n')
break;
slen=0;
source[slen++]=str;
sym=0;
while(true){
str=getchar();
if(str==' '){
sym=1;
tlen=0;
continue;
}
if(str=='\n')
break;
if(!sym)
source[slen++]=str;
else
target[tlen++]=str;
}
source[slen]='\0';
target[tlen]='\0';
Hash(0);
}
tlen=0;
while(true){
str=getchar();
if(str=='\n')
break;
tlen=0;
target[tlen++]=str;
while(true){
str=getchar();
if(str=='\n')
break;
target[tlen++]=str;
}
target[tlen]='\0';
Hash(1);
}
return 0;
}
后来用map映射做,1532ms,17340K下面是代码:
#include <iostream>
#include <string>
#include <map>
using namespace std;
map<string,bool> flag;
map<string,string> check;
char source[20];
char target[20];
int slen,tlen;
int main(){
char str;
bool sym;
while(true){
str=getchar();
if(str=='\n')
break;
slen=0;
source[slen++]=str;
sym=0;
while(true){
str=getchar();
if(str==' '){
sym=1;
tlen=0;
continue;
}
if(str=='\n')
break;
if(!sym)
source[slen++]=str;
else
target[tlen++]=str;
}
source[slen]='\0';
target[tlen]='\0';
flag[target]=true;
check[target]=source;
}
/*while(true){
str=getchar();
if(str=='\n')
break;
tlen=0;
target[tlen++]=str;
while(true){
str=getchar();
if(str=='\n')
break;
target[tlen++]=str;
}
target[tlen]='\0';
if(flag[target])
cout << check[target] << endl;
//printf("%s\n",check[target]);
else
//printf("en\n");
cout << "eh" << endl;
}*/
while(cin >> target){
if(flag[target])
cout << check[target] << endl;
//printf("%s\n",check[target]);
else
//printf("en\n");
cout << "eh" << endl;
}
return 0;
}
仔细分析了一下,map交hash算法的时间优势(空间优势很明显)
1)首先map在输入english和foreign时,是来一个存一个,不需要比较,而哈希每输入一个都要进行比较,并且要耗时求key。
2)然后就是输出阶段,map直接根据映射关系判断是否存在foreign,而哈希则要求key值,比较,然后得出输出
相较而言,map的时间优势主要体现在输出阶段。
最后我又写了一个快排+二分的算法,2544k+829ms,时间和空间更优化了。
下面是代码:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define Max 100010
typedef struct Node{
char english[12];
char foreign[12];
}node;
node record[Max];
bool cmp(const node &p,const node &q){
if(strcmp(p.foreign,q.foreign)<0)
return 1;
return 0;
}
int slen,tlen;
char source[12],target[12];
void find(int n){
int left=0,right=n-1,middle;
while(left<=right){
middle=(left+right)/2;
if(strcmp(record[middle].foreign,target)<0)
left=middle+1;
else if(strcmp(record[middle].foreign,target)==0){
//printf("%s\n",record[middle].english);
cout << record[middle].english << endl;
return ;
}
else
right=middle-1;
}
//printf("eh\n");
cout << "eh" << endl;
}
int main(){
char str;
bool sym;
int index=0;
while(true){
str=getchar();
if(str=='\n')
break;
slen=0;
source[slen++]=str;
sym=0;
while(true){
str=getchar();
if(str==' '){
sym=1;
tlen=0;
continue;
}
if(str=='\n')
break;
if(!sym)
source[slen++]=str;
else
target[tlen++]=str;
}
source[slen]='\0';
target[tlen]='\0';
strcpy(record[index].english,source);
strcpy(record[index++].foreign,target);
}
sort(record,record+index,cmp);
//for(int i=0;i<index;i++)
//printf("%s\n",record[i].foreign);
while(cin >> target)
find(index);
return 0;
}
分析map和快排+二分的时间复杂度,我发现一个很奇怪的现象:
快排输入阶段和map一样,输入完毕要sort排序,时间多消耗1000log1000,输出阶段还要二分查找,因此理论上来说map要快一些,实际上快排却更快,原因就只可能是map本身这种数据结构就很耗时,具体原理可以参考STL标准程序库,这里不详细介绍了。