题目:打印文章中出现频率最高的十个单词
收到题目的时候马上想到上学期编译原理的程序可以借鉴,中午睡觉的时候想到了点思路,首先从文件中逐个读出字符,在组合成完整单词放入一个缓冲字符数组中,在复制到结构体数组中(结构体包括两个成员:number记录出现次数,string记录单词),之后再根据数量进行排序(简单排序),然后打印。
睡醒觉了开始编程序,因为是在在以前程序基础上改动所以省了不少时间而且程序也不长所以用了一个小文本验证通过后就觉得应该没什么大问题了。但是错了。。。题目要求文章在300k到500k,接下俩的两个整整的半天都在调试程序,猜想着是不是算法的问题,这么大的数据根本执行不了,几乎都快放弃另起炉灶了,另外再循环结束条件的控制上也费了很大功夫,然而,今天上午突然柳暗花明又一村,通过了。。
程序如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #define N 500000 5 struct 6 { 7 double number; 8 char string[40]; 9 }word[N]; 10 void main() 11 { /***************读文件*************/ 12 FILE * fp; 13 char ch,filename[10]; 14 printf("请输入所用文件名:"); 15 scanf("%s",filename); 16 if((fp=fopen(filename,"r"))==NULL) 17 { 18 printf("打开文件出错"); 19 exit(0); 20 } 21 /**************读单词**************/ 22 int i=0,j,k; 23 double count1=0,count2=0; //count1为文章单词总数,count2为文章不重复单词总数。 24 ch=fgetc(fp); //fgetc函数从文章中逐个读取字符。 25 26 for(i=0;i<N;i++) 27 { 28 count1++; 29 int countenter=0; 30 char c[20]={' '}; //暂时储存字符串 31 k=0; //每次循环k从零开始,记录单词长度。 32 //while(ch==' '||ch==10||ch==9||ch==','||ch=='.'||ch=='?'||ch=='!'||ch=='$' 33 //||(ch>='0'&&ch<='9')||ch==34||ch=='('||ch==')'||ch==':'||ch=='#') 34 while((ch<39&&ch>=0)||((ch>39)&&(ch<45))||((ch>45)&&(ch<65))||((ch>90)&&(ch<97))||(ch>122)) 35 //当遇到非英文单词时跳过 36 { 37 ch=fgetc(fp); 38 } 39 if(ch==EOF) break;//文章结束标志,循环跳出结束 40 while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||ch==45||ch==39) 41 { 42 c[k]=ch; 43 k++; 44 ch=fgetc(fp); 45 } 46 strcpy(word[i].string,c); 47 // if(strcmp(word[i].string," ")==0) 48 // break; //文章结束,循环结束。 49 // else 50 // count1++; 51 word[i].number=1; 52 count2++; 53 if(i!=0) 54 { 55 //和出现过的单词进行比对 56 for(j=0;j<i;j++) 57 { 58 if(strcmp(word[j].string,word[i].string)==0) 59 { 60 word[j].number++; 61 i--; 62 count2--; 63 //printf("b"); 64 } 65 } 66 } 67 //i++; 68 } 69 70 /******根据单次出现次数进行排序******/ 71 double t; 72 char str[20]; 73 for(i=0;i<10;i++) 74 { 75 for(j=i+1;j<count2;j++) 76 { 77 if(word[i].number<word[j].number) 78 { 79 t=word[i].number; 80 word[i].number=word[j].number; 81 word[j].number=t; 82 strcpy(str,word[i].string); 83 strcpy(word[i].string,word[j].string); 84 strcpy(word[j].string,str); 85 } 86 } 87 } 88 89 /*****************打印****************/ 90 printf("出现频率前十位单词打印结果:\n出现次数 频率 单词\n"); 91 for(i=0;i<10;i++) 92 { 93 printf("%4.0f",word[i].number); 94 printf(" "); 95 printf("%4.2f",(word[i].number/count1*100)); 96 printf("%s","% "); 97 puts(word[i].string); 98 } 99 //printf("%f",count1); 100 //printf("%f",count2); 101 }
运行结果:
在调试中出现的主要问题:
1、while((ch<39&&ch>=0)||((ch>39)&&(ch<45))||((ch>45)&&(ch<65))||((ch>90)&&(ch<97))||(ch>122))
曾经想视图列举所有文章中出现的非字母的情况,发现很难列举全,后来用了列举反面的方法,只不过循环结束的条件不再是一个空的字符串,上网搜索了fgetc函数的使用方法,发现结束的条件就是ch==EOF,枉我在此处墨迹了半天。。。