第三篇
一.先贴题目
1109 综合实验:文件操作与字符处理
在当前目录中存在文件名为”case1.in”(其中case后为数字1,不是字母l,写错提交后会判错)的文本文件,
其内容为一篇英文文章(以EOF作为结束标志)。现要求读取该文本文件内容,统计文章中每个单词出现的次数,
并输出出现次数最多的前5个单词及其出现次数(按出现次数由多到少的顺序输出,次数相同时按字典顺序输出,
不足5个单词时,按序输出全部单词)。程序中注意如下细节:
(1) 空格、标点符号与回车符起到分隔单词的作用。
(2) 文章一行的末尾可能有连字符,出现连字符时,该行最末的字符串与下行最先出现的字符串构一个单词;
(3) 名词缩写算一个单词;
(4) 数字不算单词;
(5) 单词不区分大小写;
(6) 输出时单词全使用小写;
#include "stdio.h"
#include "math.h"
#include "string.h"
#include "stdlib.h"
_______________________
main()
{
_______________________
}
输入格式
文件case1.in中一篇英文文章,包含多段文字,单词数不超过10000,每个单词不超过20个字符
输出格式
按题意输出答案
输入样例
(如case1.in内容如下)
I am a student. My school is SCAU. It is a beau-
tiful university. I like it.
输出样例
a 2
i 2
is 2
it 2
am 1
二.思路分析
这是比较接近于最近写的一个实验题,也是第一个实验题。这道题的要求比较多,从题目的EOF开始,说明用fgetc 函数来读取文件好一点,一开始是用fgets来做,多设置了一个变量来存储有n行,但是还不如用fgetc,反正基本操作都差不多,少一个变量,也少一点思考量。
这道题大概要分成几个步骤或者说模块:
- 先 分离出单词来。
- 统计所有单词的全部出现个数(包括重复的也统计),用sum[i]存起来
- 去除掉同样的单词的个数并置为0
- 将单词为空串的个数置为0
- 对全部,排sum[i]序,把大的放在前面
- 找的非0的sum[i],那样就能知道总共有几个非0的有效的唯一单词的个数
- 再来对全部,将sum[i]相同的单词按序来排
- 按照题目条件,如果有效的唯一单词的个数大于等于5,就输出前5的word[i] 和sum[i];如果小于5就全部输出。
三。具体代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fp = fopen("case1.in","r");
char ch;
char word[50100][21];
//这里设置的单词数组的大小要较大于10000,
int i=0;
int j=0;
int t,k;
int g;
int sum[10100]={0};
int nozerolen; //代表非0的唯一单词的个数
int wordsum; //代表单词的全部个数
/*
分离单词
*/
while((ch=fgetc(fp))!=EOF)
{
if(ch<='Z'&&ch>='A')
ch+=32;
if(ch =='-')
{
ch = fgetc(fp);
if(ch=='\n')
continue;
else
{
i++;
j=0;
//continue;
}
/*
- 的情况比较多样,如果-后是\n 那么就和前面的是同一个单词,跳过就好,如果-后是其他东西,那就再开下一个单词来存,同时不忘记将j重置为0.
*/
}
if(ch=='\n')
continue;
//回车不作为分离单词的因素。
if(ch==' '||ch==','||ch=='='||ch=='.')
{
i++;
j=0;
continue;
/*
其中 = . , ‘ ’作为分离单词的四大符号。
*/
}
if(ch>='0'&&ch<='9')
{
continue;
//数字不作为单词的成分
}
word[i][j++]=ch;
//利用二维数组来存取字符
}
wordsum = i;
//获取单词的个数
wordsum++;
//由于从0开始,转化为常规操作从1开始数的 因此变大一个。
/*
统计所有出现的单词的出现的次数,即便重复也同样统计。
*/
for(t=0;t<wordsum;t++)
{
for(k=0;k<wordsum;k++)
{
if(strcmp(word[t],word[k])==0)
{
sum[t]++;
}
}
}
/*
对于单词一样的其他单词将它们的单词出现次数置成0.
*/
for(t=0;t<wordsum-1;t++)
{
for(k=t+1;k<wordsum;k++)
{
if(strcmp(word[t],word[k])==0)
{
sum[k]=0;
}
}
}
//将空串置成0
for(i=0;i<wordsum;i++)
{
if(strlen(word[i])==0)
{
sum[i] =0;
}
}
/*
进行冒泡排序,对于全部单词,从大到小进行排序。
这里注意在替换单词出现次数的时候,要将单词也一起替换。
*/
for(t=0;t<wordsum-1;t++)
{
for(k=0;k<wordsum-1-t;k++)
{
if(sum[k]<sum[k+1])
{
int temp;
temp = sum[k+1];
sum[k+1] = sum[k];
sum[k] = temp;
char tt[30];
strcpy(tt,word[k+1]);
strcpy(word[k+1],word[k]);
strcpy(word[k],tt);
}
}
}
/*
计算出非0的唯一单词的个数。
*/
for(t=0;t<wordsum;t++)
{
if(sum[t]==0)
{
break;
}
}
nozerolen = t+1; //也是一样转化为常规的从1开始计算
/*
再对全部非0的单词数来排序,针对于 那些sum相同的但序在后的,排成同sum序在前
*/
for(t=0;t<nozerolen-1;t++)
{
for(k=0;k<nozerolen-1-t;k++)
{
if(sum[k]==sum[k+1]&&strcmp(word[k],word[k+1])>0)
{
int temp;
temp = sum[k+1];
sum[k+1] = sum[k];
sum[k] = temp;
char tt[30];
strcpy(tt,word[k+1]);
strcpy(word[k+1],word[k]);
strcpy(word[k],tt);
}
}
}
/*
按题目要求的,非0数大于5,就输出前5,如果小于5,就输出全部。
*/
if(nozerolen<5)
{
for(g=0;g<nozerolen;g++)
{
printf("%s %d\n",word[g],sum[g]);
}
}
else
{
for(t=0;t<5;t++)
printf("%s %d\n",word[t],sum[t]);
}
fclose(fp);
}
四.总结反思
其实感觉这道题,还是没做好,因为只是处理了 ‘=’这种特殊情况,可是实际上还可以是其他的特殊字符。还有就是在分离单词那一块,实际上由于,空格并非能全部适用于全部的分离单词的情况,所以会读取到一些空串,才有后面的将空串置0的操作。这道题感觉最复杂的是分离出单词来,其他的就是一些操作,比如统计全部单词出现的次数,再对于出现过的单词的sum[i]置成0,然后是将空串的sum[i]置成0,再排sum[i]的序,再统计非0的个数,再排让sum同序前的 在前,最后就是按要求输出了。分离单词这一块应该可以再细分出一些情况,让空格转变成可以用来分隔单词的标志,也可以不是,这样就不会读到空串,在数组设置的时候也可以小一些。