题目描述:
某文本文件由"字符"组成,"字符"被"分割符"分割为"单词"。
要求程序接受指定文件,分析出其有哪些"单词"组成,并统计每一个"单词"的出现次数,
最后根据出现次数由少到多排序,输出"单词"列表。
严格定义如下:
:= 定义
<文件> := <元素> 的0次或多次重复
<元素> := { <分割符> | <单词>}
<分割符> := <分割字符> 的1次或多次重复
<分割字符> :={ 空格符 | TAB符 | 回车符 | 换行符}
<单词> := { 非<分割字符>的字符} 的1次或多次重复
程序输入格式:
在命令提示符下
程序名 <指定的文件>
程序输出格式:
输出到标准输出:
<出现次数最少的单词> <其出现次数>
<出现次数次少的单词> <其出现次数>
。。。
<出现次数最多的单词> <其出现次数>
补充要求:
程序能处理的文件大小,单词大小,仅受计算机内存和硬盘空间的限制。
任何情况下,不能出现崩溃,不正常退出,内存泄漏,令用户感觉莫名其妙的结果。
例:
------文件内容开始-----
aa bbb aa
------文件内容结束-----
输出结果:
bbb 1
aa 2
* 只能用C。”strtok()”不能用。排序使用库函数”qsort”。
程序代码:
/*************************************************************************************
*FILE:Count_Sort.cpp
*DESCRIPTION:统计文本文件中各单词出现次数,并按照次数的升序排序
*REFERENCE:none
*MODIFIED:none
*MADE BY:Micro Philosopher, 2012-11-05
*************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Count_Sort.h"
/***********************************************************
**************************主程序****************************
************************************************************/
void main()
{
char programname[NAME_LENTH],filename[NAME_LENTH];
char program[]="main.cpp",file[]="in.txt";
INPUT:
printf("Please input program name and file name.\n");
scanf("%s%s",programname,filename);
printf("\n");
if(!(strcmp(programname,program) || strcmp(filename,file))) //程序名和文件名输入正确才能进行
{
FILE *fp;
if((fp = fopen("in.txt","r"))==NULL)
{
printf("cannot open this file\n");
exit(0);
}
Fun(fp);
fclose(fp);
}
else
{
printf("No such program or file!\n");
goto INPUT; //返回重新选择
}
}
/***********************************************************
*****该函数将实现文本的读入,单词的统计排序以及文本输出*****
************************************************************/
int Fun(FILE *in)
{
int flag_FormerIsLetter = 0; //标志量,初始值置为0,当yes==0时,代表前一个字符不是字母。
char ch; //用于读取文件中的一个字符数据
char *str; //用于暂存单词的字符数据
char *tmp; //用于对*word进行内存分配
int order = 0; //单词的第几位
int file_len; //文件长度
struct Word *head = NULL;
struct Word *p;
struct Word *temp;
fseek(in,0,SEEK_END); //将文件指针移到文件结尾 fseek(文件类型指针,位移量,起始点)
file_len = ftell(in); //取得文件总长度 ftell:取得相对于文件开头的位移量
rewind(in); //将文件指针移到文件头
str = new char[file_len]; //建立用于存放一个单词的动态数组
while (!feof(in)) //feof():检测EOF文件结束标志
{
memset(str, 0, file_len); //memset():清零操作
/**************************单词输入*************************/
while (!feof(in))
{
ch = fgetc(in); //读一个字符到ch中
if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) //如果是字母
{
str[order++] = ch;
flag_FormerIsLetter = 1;
}
else //如果不是字母
{
if (flag_FormerIsLetter != 0) //代表一个单词的结束
{
order = 0; //单词位置清零
flag_FormerIsLetter = 0; //标志位清零
break;
}
}
}
/**************************出现次数统计*************************/
if (strlen(str) >= 1) //有单词出现 strlen:字符串的实际长度,不算'\0'
{
temp = head; //从头开始,依次比较
while (temp != NULL)
{
if (!(strcmp(temp->words, str))) //如果跟已存在的单词一样,则count加1 strcmp:两个参数相等
{
temp->count++;
break;
}
temp = temp->next;
}
if (temp == NULL) //如果不一样,则插入链表中。
{
p = (struct Word*)malloc(sizeof(struct Word));
p->next = head;
head = p;
tmp = (char *)malloc(file_len);
p->words = tmp;
memset(p->words, 0, file_len);
strcpy(p->words, str);
p->count = 1;
}
}
}
/**************************冒泡排序*************************/
sort(head,file_len);
/**************************输出*************************/
while (head != NULL)
{
printf("%-20s%d\n",head->words,head->count);
head = head->next;
}
return 0;
}
/***********************************************************
****对链表中的单词按出现次数进行升序排序,采用冒泡排序法****
************************************************************/
void sort(struct Word *head,int length)
{
char *str;
str = new char[length];
int n;
struct Word *p;
struct Word *p2;
for (p = head;p != NULL;p = p->next)
{
for (p2 = p;p2 != NULL;p2 = p2->next)
{
while (p2->count < p->count) //大的往下,小的往上
{
strcpy(str, p->words);
n = p->count;
strcpy(p->words, p2->words);
p->count = p2->count;
strcpy(p2->words, str);
p2->count = n;
}
}
}
}
*FILE:Count_Sort.cpp
*DESCRIPTION:统计文本文件中各单词出现次数,并按照次数的升序排序
*REFERENCE:none
*MODIFIED:none
*MADE BY:Micro Philosopher, 2012-11-05
*************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Count_Sort.h"
/***********************************************************
**************************主程序****************************
************************************************************/
void main()
{
char programname[NAME_LENTH],filename[NAME_LENTH];
char program[]="main.cpp",file[]="in.txt";
INPUT:
printf("Please input program name and file name.\n");
scanf("%s%s",programname,filename);
printf("\n");
if(!(strcmp(programname,program) || strcmp(filename,file))) //程序名和文件名输入正确才能进行
{
FILE *fp;
if((fp = fopen("in.txt","r"))==NULL)
{
printf("cannot open this file\n");
exit(0);
}
Fun(fp);
fclose(fp);
}
else
{
printf("No such program or file!\n");
goto INPUT; //返回重新选择
}
}
/***********************************************************
*****该函数将实现文本的读入,单词的统计排序以及文本输出*****
************************************************************/
int Fun(FILE *in)
{
int flag_FormerIsLetter = 0; //标志量,初始值置为0,当yes==0时,代表前一个字符不是字母。
char ch; //用于读取文件中的一个字符数据
char *str; //用于暂存单词的字符数据
char *tmp; //用于对*word进行内存分配
int order = 0; //单词的第几位
int file_len; //文件长度
struct Word *head = NULL;
struct Word *p;
struct Word *temp;
fseek(in,0,SEEK_END); //将文件指针移到文件结尾 fseek(文件类型指针,位移量,起始点)
file_len = ftell(in); //取得文件总长度 ftell:取得相对于文件开头的位移量
rewind(in); //将文件指针移到文件头
str = new char[file_len]; //建立用于存放一个单词的动态数组
while (!feof(in)) //feof():检测EOF文件结束标志
{
memset(str, 0, file_len); //memset():清零操作
/**************************单词输入*************************/
while (!feof(in))
{
ch = fgetc(in); //读一个字符到ch中
if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) //如果是字母
{
str[order++] = ch;
flag_FormerIsLetter = 1;
}
else //如果不是字母
{
if (flag_FormerIsLetter != 0) //代表一个单词的结束
{
order = 0; //单词位置清零
flag_FormerIsLetter = 0; //标志位清零
break;
}
}
}
/**************************出现次数统计*************************/
if (strlen(str) >= 1) //有单词出现 strlen:字符串的实际长度,不算'\0'
{
temp = head; //从头开始,依次比较
while (temp != NULL)
{
if (!(strcmp(temp->words, str))) //如果跟已存在的单词一样,则count加1 strcmp:两个参数相等
{
temp->count++;
break;
}
temp = temp->next;
}
if (temp == NULL) //如果不一样,则插入链表中。
{
p = (struct Word*)malloc(sizeof(struct Word));
p->next = head;
head = p;
tmp = (char *)malloc(file_len);
p->words = tmp;
memset(p->words, 0, file_len);
strcpy(p->words, str);
p->count = 1;
}
}
}
/**************************冒泡排序*************************/
sort(head,file_len);
/**************************输出*************************/
while (head != NULL)
{
printf("%-20s%d\n",head->words,head->count);
head = head->next;
}
return 0;
}
/***********************************************************
****对链表中的单词按出现次数进行升序排序,采用冒泡排序法****
************************************************************/
void sort(struct Word *head,int length)
{
char *str;
str = new char[length];
int n;
struct Word *p;
struct Word *p2;
for (p = head;p != NULL;p = p->next)
{
for (p2 = p;p2 != NULL;p2 = p2->next)
{
while (p2->count < p->count) //大的往下,小的往上
{
strcpy(str, p->words);
n = p->count;
strcpy(p->words, p2->words);
p->count = p2->count;
strcpy(p2->words, str);
p2->count = n;
}
}
}
}
/*************************************************************************************
*FILE:Count_Sort.h
*DESCRIPTION:头文件,类的定义,函数的声明
*REFERENCE:none
*MODIFIED:none
*MADE BY:Micro Philosopher, 2012-11-05
*************************************************************************************/
#define NAME_LENTH 32
struct Word
{
char *words;
int count;
struct Word *next;
};
int Fun(FILE *in);
void sort(struct Word *head,int length);
*FILE:Count_Sort.h
*DESCRIPTION:头文件,类的定义,函数的声明
*REFERENCE:none
*MODIFIED:none
*MADE BY:Micro Philosopher, 2012-11-05
*************************************************************************************/
#define NAME_LENTH 32
struct Word
{
char *words;
int count;
struct Word *next;
};
int Fun(FILE *in);
void sort(struct Word *head,int length);
in.txt和结果: