如有不对,不吝赐教
进入正题:
实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。
输入格式:
输入首先给出正整数N(≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#,表示文件结束。在N个文件内容结束之后,给出查询总数M(≤104),随后M行,每行给出一对文件编号,其间以空格分隔。这里假设文件按给出的顺序从1到N编号。
输出格式:
针对每一条查询,在一行中输出两文件的相似度,即两文件的公共词汇量占两文件总词汇量的百分比,精确到小数点后1位。注意这里的一个“单词”只包括仅由英文字母组成的、长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。单词间以任何非英文字母隔开。另外,大小写不同的同一单词被认为是相同的单词,例如“You”和“you”是同一个单词。
输入样例:
3
Aaa Bbb Ccc
Bbb Ccc Ddd
Aaa2 ccc Eee
is at Ddd@Fff
2
1 2
1 3
输出样例:
50.0%
33.3%
这道题目其实就是Hash表的应用,但是有两个点需要注意一下。
第一个就是单词的判定,这里的单词判定由题中给出,要切记:
只包括仅由英文字母组成的、长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母
大小写不同的同一单词被认为是相同的单词,例如“You”和“you”是同一个单词
所以说"a"就不能算一个单词,而"aaaaaaaaaa"和"aaaaaaaaaaaaaaaa"是同一个单词
然后就是重复率的计算,计算是这样的:
假定第一个文件话中有A个单词,第二个文件话中有B个单词,他们有C个重复的单词,那么
重复率是C/(A+B-C)
然后我的思路是为每一个文件建立一个Hash表,然后匹配的时候是用链表匹配的,其实都用Hash表会更好。
下面给出代码:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
struct WordList{
struct WordNode *head;
struct WordNode *tail;
};
struct WordNode{
char word[11]; //最多有10个字符
struct WordNode *next;
};
struct HashList{
char word[11];
struct HashList *next;
};
struct File{
struct WordList *word; //单词链表
struct HashList *table; //分配成数组 大小为allword*2
short set; //该文件是否建立了Hash表
short allword; //该文件的单词总数
};
short Hash(char *str,short N);
void GetFile(struct File *f);
struct WordList *InsertWL(struct WordList *word,char *str);
struct HashList InsertHL(struct HashList *HL,char *word);
short Cmp(struct File *f,struct WordList *word);
struct File *CreatHashTable(struct File *f);
int main(void)
{
short N,M;
short i;
short f1,f2; //比较的两个文档
short same; //两个文档的相同的单词数目
fscanf(stdin,"%hd",&N);
struct File *f[N];
for(i=0;i<N;i++){
f[i]=(struct File *)malloc(sizeof(struct File));
f[i]->allword=0;
f[i]->set=0;
f[i]->word=(struct WordList *)malloc(sizeof(struct WordList));
f[i]->word->head=f[i]->word->tail=NULL;
f[i]->table=NULL;
}
for(i=0;i<N;i++){
GetFile(f[i]); //建立文档单词库
if(f[i]->allword)
CreatHashTable(f[i]);
}
fscanf(stdin,"%hd",&M);
for(i=0;i<M;i++){
fscanf(stdin,"%hd %hd",&f1,&f2);
if(!f[f1-1]->allword||!f[f2-1]->allword)
same=0; //二者有一个为0就不用在测试了
else{
if(f[f1-1]->allword>f[f2-1]->allword)
same=Cmp(f[f1-1],f[f2-1]->word);
else
same=Cmp(f[f2-1],f[f1-1]->word);
} //用词汇少的作为被比较的 节省时间
if(!same)
printf("0.0%%\n");
else
printf("%.1f%%\n",100.0*same/(f[f1-1]->allword+f[f2-1]->allword-same));
}
return 0;
}
void GetFile(struct File *f)
{
char ch;
char str[11];
short i;
ch=fgetc(stdin);
while(!(ch<='z'&&ch>='a')&&!(ch<='Z'&&ch>='A'))
ch=fgetc(stdin);
while(ch){ //以换行和文件尾结束
if(ch=='\n'){
ch=fgetc(stdin);
if('#'==ch){
ch=fgetc(stdin);
if('\n'==ch||!ch)
break;
}
}
while((!(ch<='z'&&ch>='a')&&!(ch<='Z'&&ch>='A'))&&'\n'!=ch&&ch)
ch=fgetc(stdin); //除去非英文字符
if('\n'==ch)
continue;
i=0;
do{
str[i]=ch;
if(str[i]>='A'&&str[i]<='Z')
str[i]=str[i]-'A'+'a'; //改为小写字母
i++;
ch=fgetc(stdin);
}while(((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A'))&&i<11);
if(i<3)
continue;
if(i>10){
str[10]='\0';
while(((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')))
ch=fgetc(stdin); //除去大于10个字符长度单词后的多余字符
}
else
str[i]='\0'; //结束符号
if(InsertWL(f->word,str)) //加入单词表成功
f->allword++;
}
return ;
}
struct WordList *InsertWL(struct WordList *word,char *str)
{
struct WordNode *cur=word->head;
struct WordNode *newOne;
newOne=(struct WordNode *)malloc(sizeof(struct WordNode));
newOne->next=NULL;
strcpy(newOne->word,str);
if(!word->head){
word->head=newOne;
word->tail=newOne;
return word;
}
if(!strcmp(cur->word,str)){
free(newOne);
newOne=NULL;
return NULL;
}
while(cur&&strcmp(cur->word,str))
cur=cur->next;
if(cur){
free(newOne);
newOne=NULL;
return NULL;
} //已存在该单词
word->tail->next=newOne;
word->tail=newOne;
return word;
}
short Hash(char *str,short N)
{
short key=0;
short seed=131;
while(*str){
key=key*seed+(*str++);
if(key>=N)
key=key%N;
while(key<0)
key+=N;
}
return key;
} //字符串Hash
short Cmp(struct File *f,struct WordList *word)
{
short same=0;
short size=f->allword*2;
short key;
struct WordNode *curWord=word->head;
struct HashList *curHash;
while(curWord){
key=Hash(curWord->word,size);
curHash=&(f->table[key]);
while(curHash&&strcmp(curHash->word,curWord->word))
curHash=curHash->next;
if(curHash)
same++;
curWord=curWord->next;
}
return same;
}
struct File *CreatHashTable(struct File *f)
{
struct WordNode *cur=f->word->head;
short key;
short size=f->allword*2;
short i;
f->set=1;
f->table=(struct HashList *)malloc(size*sizeof(struct HashList));
for(i=0;i<size;i++){
f->table[i].next=NULL;
f->table[i].word[0]='\0';
}
while(cur){
key=Hash(cur->word,size);
f->table[key]=InsertHL(&(f->table[key]),cur->word);
cur=cur->next;
}
return f;
}
struct HashList InsertHL(struct HashList *HL,char *word)
{
struct HashList *cur=HL;
struct HashList *newOne;
newOne=(struct HashList *)malloc(sizeof(struct HashList));
strcpy(newOne->word,word);
newOne->next=NULL;
if(!cur->word[0]){
HL=newOne;
return *HL;
}
while(cur->next)
cur=cur->next;
cur->next=newOne;
return *HL;
}
测试结果: