分解题目,决定用C语言编写:
1.打开任意英文文本文件;
2.识别每个单词;
3.计算出现频率最高的十个单词,并打印出来。
首先确定保存单词和它们出现的次数,记录单词种类数和单词总数的结构体:
识别单词时,分为四种情况:读出的字符是
1.单词开始的第一个字符
2.单词结尾
3.单词中间部分
4.非单词符号,如空格,’.‘,’,‘ ······一视同仁,过滤
typedef struct { char letter[SizeWord]; long amount; }Word; typedef struct { Word words[NumWords]; long type; long count; }WordStatistics;
从文件中读出字符并识别每个单词,记录单词数量:
wordlist->count=0; wordlist->type=0; start=0; \\标志一个单词的开始 for(i=0;i<SizeWord;i++) w[i]='\0'; while(!feof(lp)) { ch=fgetc(lp); if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')||(ch=='-')||(ch==39)) \\分析可能出现的情况,如:Tom`s、five-year-old等 { if(start==0) \\单词的开始字符出现 { start=1; wordlist->count++; i=0; w[i]=ch; } else \\单词中间部分 { if(i<SizeWord) w[++i]=ch; else { printf("单词数组溢出!"); exit(0); } } } else { if(start=1) \\一个单词结束 { start=0; w[++i]='\0'; Compareword(wordlist,w); for(i=0;i<SizeWord;i++) w[i]='\0'; } else \\不会在一个单词中出现的字符,过滤 continue; } }
将识别的单词记录在结构体数组中:
void Compareword(WordStatistics *wordlist,char w[]) { long j; int flag=0; //将该单词与已经出现并记录的单词进行比对 for(j=0;j<wordlist->type;j++) { if(strcmp(wordlist->words[j].letter,w)==0) { wordlist->words[j].amount++; //计算单词出现次数 flag=1; break; } } if(flag==0) //出现新单词 { strcpy(wordlist->words[wordlist->type].letter,w); wordlist->words[wordlist->type].amount=1; wordlist->type++; } }
找出文章中出现频率最高的10个单词:
在这部分程序的编写中出现了很多问题,
1.如果对全部的单词进行排序,会花费较大的代价,但除了出现频率最高的10个单词,其他单词的排序都没有用。
2.先挑选出10个出现频率最高的单词,再进行排序。但是这10个单词怎么挑选哪?比如5个单词中选三个,如1,4,3,5,6,将前三个作为样本,不考虑他们的顺序,只要有比前三个数大的就交换,可能得到的是6,4,3,显然结果是错误的,只好边排序(前10个),边比较,梳理单词的顺序。(突然发现如果结构体存储为链表形式比较简单。额--|||)
3.(升级版)每次比较都找出前10个单词中出现次数最小的一个,跟第10个单词之后的单词比较,如果比最小的单词大,替换最小单词。最后将找出的10个单词进行排序。单词位置的交换次数就少了很多。
如果你看到这里,那么我想问,在这样的情况下,用什么样的方法更有效?
(三种方法的计算速度还需之后的实验证明,本次程序采用第二种方法选择文章中出现频率最高的单词。)
void SelectTopwords(WordStatistics *wordlist)// { void SortWord(Word *topwords,int count); Word topwords[Toprate]; int i,j,k,n; Word temp; float num; k=wordlist->type>Toprate?Toprate:wordlist->type; for(i=0;i<k;i++) { strcpy(topwords[i].letter,wordlist->words[i].letter); topwords[i].amount=wordlist->words[i].amount; } for(j=0;j<k;j++) { for(i=0;i<k-j;i++) if(topwords[i].amount>topwords[i+1].amount) { strcpy(temp.letter,topwords[i].letter); temp.amount=topwords[i].amount; strcpy(topwords[i].letter,topwords[i+1].letter); topwords[i].amount=topwords[i+1].amount; strcpy(topwords[i+1].letter,temp.letter); topwords[i+1].amount=temp.amount; } } if(wordlist->type>Toprate) { for(j=Toprate;j<wordlist->type;j++) for(i=0;i<Toprate;i++) if(wordlist->words[j].letter>wordlist->words[i].letter) { for(n=Toprate-1;n>i;n++) { strcpy(topwords[n].letter,wordlist->words[n-1].letter); topwords[n].amount=wordlist->words[n-1].amount; } strcpy(topwords[i].letter,wordlist->words[j].letter); topwords[i].amount=wordlist->words[i].amount; break; } } printf(" 出现频率最高的10个单词"); printf("\n______________________________________________________\n"); for(i=0;i<k;i++) { num=(float)wordlist->words[i].amount/k*100; printf("\n\t%s\t\t%3.2f\n",wordlist->words[i].letter,num); } printf("\n______________________________________________________\n"); }
最后总结,在编写程序时花费时间最长的地方在选择排序的方法,文件路径的输入方法,还有结构体数组,结构体指针作为函数参数的使用(尤其是他),越改越晕,还需请大师指教T T。