7-44 基于词频的文件相似度 (30 分)

实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。

输入格式:
输入首先给出正整数N(≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#,表示文件结束。在N个文件内容结束之后,给出查询总数M(≤10
​4
​​ ),随后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%

第一种做法:直接用数组做,结果,最后一个点超时,求大佬帮看看还能怎么优化!!!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_TEXT 10001

int mystricmp(char *str1, char *str2);

typedef struct {
	char Data[MAX_TEXT][11];
	int Article_Size;
	int rea_size;
} Article;

Article artice[MAX_TEXT];
char text[20];

int main() {
	int n;
	scanf("%d", &n);
	char ch;
	for (int i = 0; i < n; i++) {
		int j = 0, size = 0, begin = 0, save = 0;
		getchar();
		while ((ch = getchar()) != '#') {
			if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
				text[j++] = ch;
				if (j == 10) {
					text[j] = '\0';
					strcpy(artice[i].Data[save++], text);
					size++;
					j = 0;
				}
			} else {
				if (j >= 3) {
					text[j] = '\0';
					strcpy(artice[i].Data[save++], text);
					size++;
				}
				j = 0;
			}
		}
		artice[i].Article_Size = size;
	}
	for (int i = 0; i < n; i++) {
		int rea_size = artice[i].Article_Size;
		for (int j = 0; j < artice[i].Article_Size; j++) {
			if (artice[i].Data[j][0] == ' ') {
				continue;
			}
			for (int k = 0; k < artice[i].Article_Size; k++) {
				if (j == k || artice[i].Data[k][0] == ' ') {
					continue;
				}
				if (mystricmp(artice[i].Data[j], artice[i].Data[k])) {
					artice[i].Data[k][0] = ' ';
					rea_size--;
				}
			}
		}
		artice[i].rea_size = rea_size;
	}
	int m, a, b;
	scanf("%d", &m);
	for (int i = 0; i < m; i++) {
		scanf("%d %d", &a, &b);
		a--;
		b--;
		int equ = 0;
		for (int j = 0; j < artice[a].Article_Size; j++) {
			int flag = 0;
			for (int k = 0; k < artice[b].Article_Size; k++) {
				if (artice[b].Data[k][0] == ' ') {
					continue;
				}
				if (mystricmp(artice[a].Data[j], artice[b].Data[k])) {
					artice[b].Data[k][0] = ' ';
					flag = 1;
					break;
				}
			}
			if (flag) {
				equ++;
			}
		}
		int total = (artice[a].rea_size - equ) + (artice[b].rea_size - equ)
				+ equ;
		printf("%.1f%%\n", (double) equ / total * 100);
	}
	return 0;
}

int mystricmp(char *str1, char *str2) {
	int flag = 1, move = 0, times = 0;
	char a = *(str1 + move);
	char b = *(str2 + move);
	while (a != '\0' && b != '\0') {
		if (!(a == b || a + ('a' - 'A') == b || a - ('a' - 'A') == b
				|| b + ('a' - 'A') == a || b - ('a' - 'A') == a)) {
			flag = 0;
			break;
		}
		move++;
		times++;
		if (times == 10) {
			break;
		}
		a = *(str1 + move);
		b = *(str2 + move);
	}
	return flag;
}


第二种做法:吸取上面的教训,发现后面再去掉相同的单词太花时间(得到去重的文章单词数量),改用链表,一个Insert就可以得到预期结果了,但还是超时最后一个点,求大佬帮看看还能怎么优化!!!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_VIS 10001
#define MAX_TEXT 101


typedef struct W{
    char Data[11];
    struct W*Next;
} WordNode;

typedef struct{
    WordNode *Words;
    int Article_Word_Size;
} Article;

Article artice[MAX_TEXT];
char text[20];

int My_Stricmp(char *str1,char *str2);
void Init_Article();
WordNode* Insert_Word(WordNode*root,char *insertWord,int *size);
int Find_Equeal_Word(WordNode *a,WordNode*b);

int main(){
    int n,i,j,size;
    scanf("%d",&n);
    char ch;
    for(i=0; i<n; i++){
        j=0;size=0;
        getchar();
        while((ch=getchar())!='#'){
            if(('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z')){
                text[j++]=ch;
                if(j==10){
                    text[j]='\0';
                    artice[i].Words=Insert_Word(artice[i].Words,text,&size);
                    j=0;
                    while((ch=getchar())){
                        if(!('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z')){
                            break;
                        }
                    }
                }
            }else{
                if(j>=3){
                    text[j]='\0';
                    artice[i].Words=Insert_Word(artice[i].Words,text,&size);
                }
                j=0;
            }
        }
        artice[i].Article_Word_Size=size;
    }
    int m,a,b,equ,total;
    scanf("%d",&m);
    for(i=0; i<m; i++){
        scanf("%d %d",&a,&b);
        a--;b--;
        equ=Find_Equeal_Word(artice[a].Words,artice[b].Words);
        total=(artice[a].Article_Word_Size-equ)+(artice[b].Article_Word_Size-equ)+equ;
        printf("%.1f%%\n",(double)equ/total*100);
    }
    return 0;
}

int My_Stricmp(char *str1,char *str2){
    int flag=0,move=0;
    char a=*(str1+move);
    char b=*(str2+move);
    while(a!='\0' && b!='\0'){
        if(!(a==b
             || a+('a'-'A')==b || a-('a'-'A')==b
             || b+('a'-'A')==a || b-('a'-'A')==a)){
            flag=1;
            break;
        }
        move++;
        a=*(str1+move);
        b=*(str2+move);
    }
    return flag;
}

void Init_Article(){
    for(int i=0; i<MAX_TEXT; i++){
        artice[i].Words=NULL;
    }
}

WordNode* Insert_Word(WordNode*root,char *insertWord,int *size){
    if(root==NULL){
        (*size)++;
        WordNode *temp=(WordNode*)malloc(sizeof(WordNode));
        strcpy(temp->Data,insertWord);
        temp->Next=NULL;
        return temp;
    }
    if(!My_Stricmp(root->Data,insertWord)){
        return root;
    }
    int flag=1;
    WordNode *move=(WordNode*)malloc(sizeof(WordNode));
    move=root;
    while(move->Next!=NULL){
        move=move->Next;
        if(!My_Stricmp(move->Data,insertWord)){
            flag=0;
            break;
        }
    }
    if(flag){
        (*size)++;
        WordNode *temp=(WordNode*)malloc(sizeof(WordNode));
        strcpy(temp->Data,insertWord);
        temp->Next=NULL;
        move->Next=temp;
    }
    return root;
}

int Find_Equeal_Word(WordNode *a,WordNode*b){
    int sum=0,pos;
    int isV[MAX_VIS]={0};
    WordNode *b_temp=(WordNode*)malloc(sizeof(WordNode));
    b_temp=b;
    while(a!=NULL){
        pos=0;
        while(b!=NULL){
            if(!isV[pos] && !My_Stricmp(a->Data,b->Data)){
                isV[pos]=1;
                sum++;
                break;
            }
            pos++;
            b=b->Next;
        }
        a=a->Next;
        b=b_temp;
    }
    return sum;
}

第三种做法:吸取上面的教训,但发现Insert的过程其实也在比较(虽然比数组好),但后面查询时候要从头遍历链表,太浪费时间,由此想到用哈希表来弄,减短查询时间,用的 EFLHash函数 + 线性探测法 解决碰撞冲突问题,这样后面就可以直接查找比较了(相同单词在相同位置,我是放弃了空间,省时间),但还是超时最后一个点,求大佬帮看看还能怎么优化!!!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_TEXT 10001
#define MAX_WORD 100

void toUp(char *str);
unsigned int ELFHash(char *str);

typedef struct{
    char Data[MAX_WORD][11];
    int Article_Size;
    int First_Pos;
} Article;

Article artice[MAX_TEXT];
char text[11];

int main(){
    for(int i=0; i<MAX_TEXT; i++){
        for(int j=0; j<MAX_WORD; j++){
            artice[i].Data[j][0]=' ';
        }
    }
    int n,firstPos;
    scanf("%d",&n);
    char ch;
    for(int i=0; i<n; i++){
        int j=0,size=0,begin=0,save=0;
        firstPos=MAX_WORD;
        getchar();
        while((ch=getchar())!='#'){
            if(('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z')){
                text[j++]=ch;
                if(j==10){
                    text[j]='\0';
                    toUp(text);
                    int pos=ELFHash(text),flag=1;
                    while(artice[i].Data[pos][0]!=' '){
                        if(!strcmp(artice[i].Data[pos],text)){
                            flag=0;
                            break;
                        }
                        pos++;
                        if(pos==MAX_WORD){
                            pos=0;
                        }
                    }
                    if(flag){
                        if(pos<firstPos){
                            firstPos=pos;
                        }
                        strcpy(artice[i].Data[pos],text);
                        size++;
                    }
                    j=0;
                    while((ch=getchar())){
                        if(!(('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z'))){
                            break;
                        }
                    }
                }
            }else{
                if(j>=3){
                    text[j]='\0';
                    toUp(text);
                    int pos=ELFHash(text),flag=1;
                    while(artice[i].Data[pos][0]!=' '){
                        if(!strcmp(artice[i].Data[pos],text)){
                            flag=0;
                            break;
                        }
                        pos++;
                        if(pos==MAX_WORD){
                            pos=0;
                        }
                    }
                    if(flag){
                        if(pos<firstPos){
                            firstPos=pos;
                        }
                        strcpy(artice[i].Data[pos],text);
                        size++;
                    }
                }
                j=0;
            }
        }
        artice[i].First_Pos=firstPos;
        artice[i].Article_Size=size;
    }
    int m,a,b,equ,pos,end;
    scanf("%d",&m);
    for(int i=0; i<m; i++){
        scanf("%d %d",&a,&b);
        a--;b--;
        equ=0;
        for(int j=artice[a].First_Pos; j<MAX_WORD; j++){
            if(artice[a].Data[j][0]==' '){
                continue;
            }
            if(!strcmp(artice[a].Data[j],artice[b].Data[j])){
                equ++;
            }
        }
        int total=(artice[a].Article_Size-equ)+(artice[b].Article_Size-equ)+equ;
        printf("%.1f%%\n",(double)equ/total*100);
    }
    return 0;
}

void toUp(char *str){
    int move=0;
    while(*(str+move)){
        if('a'<=*(str+move) && *(str+move) <= 'z'){
            *(str+move)-='a'-'A';
        }
        move++;
    }
}

unsigned int ELFHash(char *str){
	unsigned int hash = 0;
	unsigned int x = 0;
	while (*str){
		hash = (hash << 4) + (*str++);
		if ((x = hash & 0xF0000000L) != 0){
			hash ^= (x >> 24);
			hash &= ~x;
		}
	}
	return (hash & 0x7FFFFFFF)%MAX_WORD;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值