关闭

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

标签: c语言
615人阅读 评论(0) 收藏 举报
分类:

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

实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于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%

思路
目前平台上这道题的通过人数为0,当然我也还没写出PASS的代码。
提前不知道文件大小,所以必须用链表动态存储数据。注意不区分大小写。对于长度大于10的字符串,只考虑前10个字母(不能用scan_s截断字符串),每读完一个文件都必须排序出一个单向链。

【160830更新】用链表写了一个,规则已经是对的了,对于超时,只能说简单的单向链表是不可取的的机构。下面可供扩展的还有二叉树(不过也有风险)。或者推翻整个程序架构,建立一个可扩容的哈希表存放结构,这个机构包括一个字符串以及这个字符串在哪些文件中出现过。

点击访问 PTA-测验

单向链结构:(超时)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Big(a,n) ((a)>(b))?(a):(b)
/*平台不支持使用stricmp.*/
/* 评测结果 时间  结果  得分  题目  编译器     用时(ms)  内存(MB)  用户
2016-08-30 14:51    部分正确    26  5-44    gcc     2   1   569985011
测试点结果 测试点   结果  得分/满分   用时(ms)  内存(MB)
测试点1    答案正确    18/18   1   1
测试点2    答案正确    4/4     2   1
测试点3    答案正确    2/2     2   1
测试点4    答案正确    2/2     1   1
测试点5    运行超时    0/4     0   0
查看代码*/
typedef struct node *Node;
struct node {
    char*Words;
//  int Number;//考察的是词汇 量,对于重复的词汇不必要处理
    Node Next;
};

char*scan();
Node Insert(Node,char*);
void cmp(Node,Node);

int main() {
    int n;
    scanf("%d",&n);
    Node Head[101]= {0}; //初始化为空

    for(int i=1; i<=n; i++) {
//      printf("\n--\n");
        int flag=1;
        while(flag) {
            char*temp=scan();
            int len=strlen(temp);
            if(len==1&&temp[0]=='#')flag=0;
            else if(len>=3) {
//              printf("{%s}",temp);
                Head[i]=Insert(Head[i],temp);
            }
        }
//      Node temp=Head[i];
//      while(temp) {
//          printf("[%s]",temp->Words);
//          temp=temp->Next;
//      }
    }

    int m;
    scanf("%d",&m);
    while(m--) {
        int a,b;
        scanf("%d%d",&a,&b);
        cmp(Head[a],Head[b]);
    }

    return 0;
}

void cmp(Node a,Node b) {
    if(a&&b) {
        int Total=0;
        int Same=0;
        while(a&&b) {
            ++Total;
//          printf("{%s-%s}",a->Words,b->Words);
            int flag=strcmp(a->Words,b->Words);
            if(!flag) {
                ++Same;
                a=a->Next;
                b=b->Next;
            } else if(flag<0) {
                a=a->Next;
            } else {
                b=b->Next;
            }
        }
        while(a) {
            ++Total;
            a=a->Next;
        }
        while(b) {
            ++Total;
            b=b->Next;
        }
        printf("%.1f%%\n",Same*100.0/Total);
    } else printf("0.0%%\n");
}

char*scan() {
    static char temp[11];
    int i=0;
    char c;
    do {
        c=getchar();
        if(c>='A'&&c<='Z') {
            if(i<10)temp[i++]=c+'a'-'A';
        } else if(c>='a'&&c<='z') {
            if(i<10)temp[i++]=c;
        } else if(c=='#') {
            temp[i++]=c;
            break;
        } else break;
    } while(1);
    temp[i]='\0';
    return temp;
}

Node Insert(Node h,char*K) {
    if(!h||strcmp(h->Words,K)>0) {
        Node temp=(Node)malloc(sizeof(struct node));
        temp->Next=h;
//      temp->Number=1;
        temp->Words=(char*)malloc(sizeof(strlen(K))) ;
        strcpy(temp->Words,K);
        return temp;
    } else if(strcmp(h->Words,K)<0) h->Next=Insert(h->Next,K);
    return h;
}

哈希映射:(错误,还没找不到原因)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HashLenth 10007  //测试内存开销3MB,也就是不到1MB的数据个数。 
/*可能存在的坑“首先给出文件正文,最后在一行中只给出一个字符#”,所以我的scan()函数可能踩雷了。具体点说就是在某个文件里面出现#是正常的字符,而我错把它当做那个文件的结束符号。
暂时没想到怎么验证。。。*/
/* 评测结果 
时间  结果  得分  题目  编译器     用时(ms)  内存(MB)  用户
2016-08-30 18:26    部分正确    26  5-44    gcc     86  2   569985011
测试点结果 
测试点     结果  得分/满分   用时(ms)  内存(MB)
测试点1    答案正确    18/18   2   1
测试点2    答案正确    4/4     2   1
测试点3    答案正确    2/2     1   1
测试点4    答案正确    2/2     1   1
测试点5    答案错误    0/4     86  2
查看代码*/
typedef struct node *Node;
struct node {
    char*Word;
    int Reached[101];
    int Times;
};
Node Hash[HashLenth]= {0};
int Same[101][101]= {0};//Same[a][b]表示a文件和b文件的相似词汇量
int Sum[101]= {0};//各个文件的有效词汇量
int n;

int Mod(int);
char*scan();
void Insert(int ,char*);
int HashKey(char*);
void Refresh(Node,int);

int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        int flag=1;
        while(flag) {
            char*temp=scan();
            int len=strlen(temp);
            if(len==1&&temp[0]=='#')flag=0;
            else if(len>=3)Insert(i,temp);
        }
    }
    int m;
    if(scanf("%d",&m)==0)exit(1);
    while(m--) {
        int a,b;
        scanf("%d%d",&a,&b);
        if(Same[a][b])printf("%.1f%%\n",Same[a][b]*100.0/(Sum[a]+Sum[b]-Same[a][b]));
        else printf("0.0%%\n");
    }
    return 0;
}

void Refresh(Node N,int h) {
    if(N->Reached[N->Times]==h)return;//同一个文件里面出现的重复单词不累加
    ++Sum[h];//文件词汇量+1 
//  printf("[Used");
    N->Reached[++N->Times]=h;
    for(int i=0; i<N->Times; i++) {//所有包含此字符串的文件彼此Same++ 
//      printf("*");
        ++Same[N->Reached[i]][h];
        ++Same[h][N->Reached[i]];
    }
//  printf("]");
}

int HashKey(char*K) {//尽量不让他抱团
    int temp=(K[0]-'a')*32*32+(K[1]-'a')*32+K[2]-'a';
    temp*=HashLenth;
    temp/=27482;//26*32*32+26*32+26
    return temp;
}

int Mod(int Num) {
    while(Num<0)Num+=HashLenth;
    return Num%HashLenth;
}
void Insert(int h ,char*K) {
    int Key=HashKey(K);
    int flag;
    int i;
    for( i=0; i<=HashLenth/2; i++) {
        flag=Mod(Key+i*i);
        if(!Hash[flag])break;
        else if(!strcmp(Hash[flag]->Word,K)) {
            Refresh(Hash[flag],h);
            return ;
        }
        flag=Mod(Key-i*i);
        if(!Hash[flag])break;
        else if(!strcmp(Hash[flag]->Word,K)) {
            Refresh(Hash[flag],h);
            return ;
        }
    }
    if(i>HashLenth/2) {//实践证明平台的词汇量并不多 
        exit(1);//  printf("ERROR:HashLenth is not enouth!\n");
    }
//  printf("[NEW]");
    ++Sum[h];//对该文件词汇量+1 
    Hash[flag]=(Node)malloc(sizeof(struct node));
    Hash[flag]->Word=(char*)malloc(sizeof(char)*strlen(K));
    strcpy(Hash[flag]->Word,K);
    Hash[flag]->Times=0;
    Hash[flag]->Reached[0]=h;
}

char*scan() {
    static char temp[11];
    int i=0;
    char c;
    do {
        c=getchar();
        if(c>='A'&&c<='Z') {
            if(i<10)temp[i++]=c-'A'+'a';
        } else if(c>='a'&&c<='z') {
            if(i<10)temp[i++]=c;
        } else if(c=='#') {
            temp[i++]=c;
            break;
        } else break;
    } while(1);
    temp[i]='\0';
//  printf("{%s}",temp); 
    return temp;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    文章分类
    最新评论