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
#include
#include
#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
#include
#include
#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=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; iData,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
#include
#include
#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=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> 24);
			hash &= ~x;
		}
	}
	return (hash & 0x7FFFFFFF)%MAX_WORD;
}

你可能感兴趣的:(数据结构,pta,数据结构,c语言,算法)