关于计算出现频率的问题
无论在什么场合经常遇到这样的问题,要求得到一些出现频率最高的东西。例如:一篇文章中出现的哪个词语最多,或者统计网络中最受欢迎的流行语,或者网络搜索中人们输入最多的词语。这是一类常见的问题,下面以一篇英语文章中出现的频率最高的十个单词为例简单介绍一个程序。
源代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#define num 10000
#define N 40
#define M 20
char a[M];
char *id;
char word[num][M];
int wordnum[num];
int n=0,m=0,k=0,i=0,j=0;
FILE * in;
char ch,file[N];
void creat()
{
for(i=0;i<=num;i++)
{
wordnum[i]=1;
}
n=0;
while(in)
{
ch=fgetc(in);
if(!(ch>='a'&&ch<='z'||ch>='0'&&ch<='9'||ch>='A'&&ch<='Z'||ch==39))
{
k=0;
id = _strlwr( _strdup( a ) );
a[k]=0;
for(i=0;i<=n;i++)
{
if(strcmp(id,word[i])==0&&id[0]!=0)
{
wordnum[i]++;
break;
}
}
if(i>n&&id[0]!=0)
{
strcpy(word[n],id);
n++;
}
}
if(ch>='a'&&ch<='z'||ch>='0'&&ch<='9'||ch>='A'&&ch<='Z'||ch==39)
{
if(k<M)
{
a[k]=ch;
k++;
}
a[k]=0;
}
if(feof(in))
{
for(i=0;i<n;i++)
for(j=i;j<n;j++)
if(wordnum[i]<wordnum[j])
{
strcpy(id,word[j]);
strcpy(word[j],word[i]);
strcpy(word[i],id);
m=wordnum[j];
wordnum[j]=wordnum[i];
wordnum[i]=m;
}
for(i=0;i<10;i++)
{
printf("%s %d \n",word[i],wordnum[i]);
}
exit(0);
}
}
}
int main()
{
printf("输入英文的文件名:");
scanf("%s",file);
in=fopen(file,"r");
if(in)
{
creat();
}
else
{
printf("无法打开文件\n");
exit(0);
}
fclose(in);
}
这是一个非常简单的C语言程序,一共有百行左右,主要包含两部分,一部分是文件的打开与关闭,另一部分就是文件的读取及单词的计数。虽然程序非常简单,但却要注意许多细节,首先是读取时单词的区分因为读取是按字符读取的,这就需要将单词一个个分离出来,我是以非字母,非数字,非“ ’”作为一个单词的分隔符的,其中要注意“ ’”,因为有缩写的单词,例如can’t,don't等。刚开始就没注意到这一点,出现了错误。在这之后要将单词存入字符串数组(其实也可以选用结构体来记入单词及其个数),这其中用到了字符串处理函数,要注意对单词进行比较,将相同单词计数加一。在存入时同样出现了问题,因为读取存入时用的是同一个字符串数组,这样单词有长有短,就出现了这样的问题,例如,第一个单词是written,这样a[0]~a[6]分别是w、r、i、t、t、e、n,第二个单词是in,a[0]=i,a[1]=n,将a复制过去时就成了initten。之后将a[k]=0才解决了问题。而a[k]=0还解决了另一个问题,就是出现单词间隔不是一个时,a[N]中已存入单词会再一次复制比较致使出现计数错误,另a[k]=0,就排除了出现这种情况的可能。最后对各单词出现个数进行比较再输出,到此这个小程序就已经完成了。不过在查看输出结果时,突然发现单词中会有首字母大写的情况,例如,And和 and,这样就成了两个单词,所以有进行了修改加进了strlwr函数将大写都改为小写,再进行比较。这才最终完成。
但是这个程序并不是很完善的,还可以进行许多添加,例如读入文件可以加进文件目录的选择输入,还有添加根据需要输出频率最多或最少的不同个数的单词。然而这只是作为这类问题说明的一个小程序,简单点更容易理解,就没有再进行添加。下面是对英文歌曲昨此情可待的统计结果: