题目描述:
某文本文件由"字符"组成,"字符"被"分割符"分割为"单词"。
要求程序接受指定文件,分析出其有哪些"单词"组成,并统计每一个"单词"的出现次数,
最后根据出现次数由少到多排序,输出"单词"列表。
严格定义如下:
:= 定义
<文件> := <元素> 的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和结果: