题目
统计输入英文文章段落中不同单词(单词有大小写之分, 但统计时忽略大小写)各自出现的次数。 输入段落中所含单词的总数不超过100,最长单词的长度不超过20个字母.
输入
一个包含若干句子的段落, 每个句子由若干英文单词组成. 除空格, 逗号和句号外, 这些输入的句子中不含其他非字母字符, 并且, 逗号和句号紧跟在它前面的英文单词后面, 中间没有空格. 段落最后一个字符是回车符, 表示输入结束.
输出
若段落中共有M个不同的英文单词,则按照其在段落中出现的先后顺序输出M行,各行的格式为: 单词中所有字母均用大写形式输出(最长的单词顶格输出,它前面没有多余的空格;其余单词与其右对齐)+冒号+N个*号+该单词在段落中的出现次数N
样例输入
This is a test. This test is easy. This is a test. This test is easy.
样例输出
THIS:****4
IS:****4
A:**2
TEST:****4
EASY:**2
解题思路
本题类似于PAT乙级1080:MOOC期终成绩。该类题目都是统计一个对象的多个属性,故需要用到qsort和bsearch函数,前者用于对该对象按照某一、或者多个属性排序,后者用于查找该对象是否曾经出现过。
这类题目的解题思路都是利用结构体数组存储每一个对象,在main当中不断的读入信息,先查找该信息的对象是否已经“建档”(即存在于结构体数组中),如果是,将该对象对应的属性更新,否则,重新为该对象“建档”。最后,再按照要求输出即可。
易错点
使用bsearch(二分法查找)前应先使用qsort。
代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct words{
char name[21];//单词内容
int n;//出现次数
int th;//出现顺序
};
int cmp1(const void *a, const void *b){
struct words c = *(struct words *)a;
struct words d = *(struct words *)b;
return strcmp(c.name,d.name);
}
int cmp2(const void *a, const void *b){
char *c = (char *)a;
struct words d = *(struct words *)b;
return strcmp(c,d.name);
}
int cmp3(const void *a, const void *b){//按照出现顺序排序
struct words c = *(struct words *)a;
struct words d = *(struct words *)b;
return c.th - d.th;
}
int main()
{
struct words W[100];//所含单词的总数
struct words *p;
char temp[21];
int num = 0;
int i,j,len,max_len = 0;
while (scanf("%s",temp)!=EOF){
len = strlen(temp);
while (temp[len-1]==',' || temp[len-1]=='.'){//删除句末的标点符号
temp[--len] = '\0';
}
if (len>max_len)
max_len = len;//找到最长长度的单词
for (i=0;i<len;i++)//转为大写字母
if (temp[i]>96 && temp[i]<123)
temp[i]-=32;
qsort(W,num,sizeof(W[0]),cmp1);
p = (struct words *)bsearch(temp,W,num,sizeof(W[0]),cmp2);
if (p==NULL)
{
W[num].n = 1;
strcpy(W[num].name,temp);
W[num].th = num;
num++;
}
else
(*p).n++;
}
qsort(W,num,sizeof(W[0]),cmp3);
for (i=0;i<num;i++){
len = strlen(W[i].name);
for (j=0;j<(max_len-len);j++)
printf(" ");
printf("%s:",W[i].name);
for (j=0;j<W[i].n;j++)
printf("*");
printf("%d\n",W[i].n);
}
return 0;
}