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

原创 2016年08月30日 12:33:39

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;
}
版权声明:写这些东西还是问了交流进步,如果你有不同的方法、见解,欢迎交流分享。文章中附的代码只传达当时我的一种做法,并非我认为最好的。

PAT 基于词频的文件相似度 (set) -- 解题报告

解题思路每个文件内的单词存放到单独的一个 set 中。询问时直接遍历其中一个 set(必须是 size 较小的那个,否则会超时在最后一个测试点),用 count() 查找另一个 set 中存不存在这个...
  • dreamer_blue
  • dreamer_blue
  • 2017年03月05日 20:39
  • 295

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

5-11 基于词频的文件相似度 (30分)实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超...
  • xiaobai12123
  • xiaobai12123
  • 2017年03月28日 22:33
  • 346

Python简单实现基于VSM的余弦相似度计算

Python简单实现基于VSM的余弦相似度计算 转载原地址:http://blog.csdn.net/eastmount/article/details/498981...
  • Johline
  • Johline
  • 2017年03月03日 14:15
  • 628

文件相似度比对工具的设计与实现

一、背景与目标 我们业务维护了两个代码仓库,两端的代码很多都是一个平台先开发好,几乎直接copy到另一个仓库。于是产生了一个技术需求,实现这两个仓库代码复用。在技术预研阶段,需要统计早先copy的...
  • lizitao
  • lizitao
  • 2017年01月17日 17:23
  • 1861

Solr进阶之Solr综合文本相似度的多因素权重排序实现

现在有个需求是这样子的: 需要计算搜索词的权重设置其为总排序权重的0.6,其他因素的权重为0.4 其他因素中还有详细的划分. 这里我们用Solr如何来实现?众所周知solr默认的排序方式为按照文...
  • sqh201030412
  • sqh201030412
  • 2016年12月23日 17:13
  • 3861

TF-IDF与余弦相似度

在文本处理中,经常用到TF-IDF,其英文是Term Frequency - Inverse Document Frequency,词频-逆文档频率。 作用是提取文档的关键词,思路是文档的出现最多的...
  • qq_23617681
  • qq_23617681
  • 2016年05月21日 18:12
  • 1080

如何计算两个文档的相似度(二)

注:完全进行了测试,并附有完整代码: # -*- coding: cp936 -*- from gensim import corpora, models, similarities import...
  • qq_27231343
  • qq_27231343
  • 2016年07月17日 17:30
  • 2728

几种文本相似度算法的C++实现

1、最小编辑距离
  • fdsdfdsf
  • fdsdfdsf
  • 2014年05月23日 18:55
  • 1594

python 商品名称相似度查找(difflib库和结巴分词的运用)

今天同事被告知要写一个查询商品相似度的系统,我以为事类似推荐系统一样的高大上系统,心中暗自庆幸没有被委以如此重任,不然在紧迫的时间里学习实现这套系统一定会睡眠不足的,后来同事讲解后我才知道只是一个商品...
  • u013055678
  • u013055678
  • 2016年09月29日 02:53
  • 11159

ruby写一个文件内容相似性比较的代码

1.相似度定义 我们定义,则,我们设,则,|C|=s,则相似度p=,p(0,1) 2.相似度检测算法设计 算法设计: 定义4个字符为一个字符串,将T1,T2分割成若干字符串,...
  • mydo
  • mydo
  • 2014年12月01日 09:55
  • 1427
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:5-44 基于词频的文件相似度 (30分)
举报原因:
原因补充:

(最多只允许输入30个字)