英文单词统计程序
2017-04-30 20:31
246 查看
本文使用hash表实现一个英文单词统计程序,输入英文段落文件EnglishFile.txt,统计结果按顺序输出到Stat_result.txt 文件当中。
特别声明,小程序在VC6.0中验证通过。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* *********************************************************
* 文件名: 英文单词统计程序
* 基本需求:利用有限状态机实现英文文件的单词统计
* 作者: 韩立忠
* 创建时间:2011.07.17
/* ******************************************************* */
/* ******************** 定义头文件 *********************** */
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
/* ********************** 宏定义 ************************* */
#define HASH_SIZE (26) // hash表索引大小
#define WORD_LEN (32) // 存放单词的缓冲长度
/* ******************* 定义数据结构 ********************** */
// hash冲突链单词结点
typedef struct dNode_s
{
struct dNode_s *prev;
struct dNode_s *next;
char *word;
unsigned int count; // 重复单词计数
}dNode_t;
// hash冲突链头结点
typedef struct dList_s
{
dNode_t *head;
dNode_t *tail;
unsigned int length; // 冲突链长度
}dList_t;
// 字符类型的枚举
typedef enum
{
LETTER = 0, // 字母
NUMBER, // 数字
COMM_PUNCT, // 常用标点,包括(, . : ; ! ?)
DOUBLE_CHAR, // 双字符,包括('' "" () [] {} <>)
OTH_VISI_CHAR, // 除上述的其它可显字符
SPACE_OR_ENTER, // 空格,tab或回车
TOTAL_TYPE = SPACE_OR_ENTER
};
/* ******************* 定义全局变量 ********************* */
unsigned int g_StatResult[TOTAL_TYPE] = {0}; // 各种类型的统计结果
/* ********************* 函数声明 *********************** */
void StatisticFunc(dList_t *); // 英文单词统计主函数
unsigned int AnalyzeChar(char); // 分析字符函数
unsigned int HashFunc(char *); // hash索引计算函数
void InitHash(dList_t *); // hash表初始化函数
void AddWord2Hash(dList_t *, char *); // hash缓存单词插入函数
void PrintFunc(dList_t *); // hash缓存遍历打印函数
void FreeHash(dList_t *); // hash缓存释放函数
void main(void)
{
dList_t hashTable[HASH_SIZE];
InitHash(hashTable);
StatisticFunc(hashTable);
PrintFunc(hashTable);
FreeHash(hashTable);
}
/* 统计函数:统计英文单词数并存于hash表中,对于其余各种字符仅统计个数 */
void StatisticFunc(dList_t *table)
{
FILE *fp = NULL;
char ch = 0;
char flag = 0; // 1标识遇到单引号,0代表读完或未遇到单引号
char *word = NULL;
unsigned int wordLen = 0;
fp = fopen("EnglishFile.txt", "rt");
if (NULL == fp)
{
printf("StatisticFunc:Cannot Open File!\n");
exit(0);
}
word = (char *)malloc(WORD_LEN * sizeof(char));
if (NULL == word)
{
printf("StatisticFunc:Insufficient Memory!\n");
exit(0);
}
memset(word, 0, WORD_LEN * sizeof(char));
ch = fgetc(fp);
while (ch != EOF)
{
switch (AnalyzeChar(ch))
{
case LETTER: // 字母
{
wordLen = 0;
do
{
/* 若在单词首遇到字符',则视其为单引号,且读此单词过程中遇到的'视为
另一半单引号,并确定已读完完整单词;否则,视字符'为单词缩写符 */
if ((1 == flag) && ('\'' == ch))
{
flag = 0;
g_StatResult[DOUBLE_CHAR]++;
ch = fgetc(fp);
break;
}
if ((ch >= 'A') && (ch <= 'Z'))
{
ch += 32;
}
*(word + wordLen) = ch;
ch = fgetc(fp);
wordLen++;
}while ((LETTER == AnalyzeChar(ch)) || ('-' == ch) || ('\'' == ch));
*(word + wordLen) = '\0';
AddWord2Hash(table, word);
g_StatResult[LETTER]++;
break;
}
case NUMBER: // 数字
{
do
{
ch = fgetc(fp);
}while (NUMBER == AnalyzeChar(ch));
g_StatResult[NUMBER]++;
break;
}
case COMM_PUNCT: // 常见标点符号
{
g_StatResult[COMM_PUNCT]++;
ch = fgetc(fp);
break;
}
case DOUBLE_CHAR: // 双字符,单词首遇到单引号,flag置1
{
if ('\'' == ch)
{
flag = 1;
}
g_StatResult[DOUBLE_CHAR]++;
ch = fgetc(fp);
break;
}
case OTH_VISI_CHAR: // 其他可显字符
{
g_StatResult[OTH_VISI_CHAR]++;
ch = fgetc(fp);
break;
}
case SPACE_OR_ENTER: // 空格,tab或回车
{
ch = fgetc(fp);
break;
}
default:
{
break;
}
}
}
g_StatResult[DOUBLE_CHAR] /= 2; // 双字符总数,为计数结果除以2
fclose(fp);
free(word);
}
/* 简单分析字符的类型 */
unsigned int AnalyzeChar(char ch)
{
if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
{
return LETTER;
}
else if ((ch >= '0') && (ch <= '9'))
{
return NUMBER;
}
else if ((',' == ch) || ('.' == ch) || ('?' == ch) || ('!' == ch) || (':' == ch) || (';' == ch))
{
return COMM_PUNCT;
}
else if (('\'' == ch) || ('"' == ch) || ('(' == ch) || (')' == ch) ||
('[' == ch) || (']' == ch) || ('{' == ch) || ('}' == ch) || ('<' == ch) || ('>' == ch))
{
return DOUBLE_CHAR;
}
else if ((ch != ' ') && (ch != '\n') && (ch != '\t')) // 其他可显字符统计
{
return OTH_VISI_CHAR;
}
else
{
return SPACE_OR_ENTER;
}
}
/* hash表初始化函数 */
void InitHash(dList_t *table)
{
unsigned int idx = 0;
if (NULL == table)
{
printf("InitHash:Insufficient Memory!\n");
exit(0);
}
//memset(table, 0, HASH_SIZE * sizeof(dList_t))
for (idx = 0; idx < HASH_SIZE; idx++)
{
table[idx].head = NULL;
table[idx].tail = NULL;
table[idx].length = 0;
}
}
/* hash表单词缓存,升序插入单词;对于重复出现的单词仅计数重复次数,不执行插入*/
void AddWord2Hash(dList_t *table, char *word)
{
unsigned int idx = 0;
unsigned int buffLen = 0;
dNode_t *pTmpNode = NULL;
dNode_t *pNewNode = NULL;
if ((NULL == table) || (NULL == word))
{
printf("AddWord2Hash:Insufficient Memory!\n");
exit(0);
}
idx = HashFunc(word);
if (idx >= HASH_SIZE)
{
printf("AddWord2Hash:HashKey Error!\n");
exit(0);
}
pNewNode = (dNode_t *)malloc(sizeof(dNode_t));
if (NULL == pNewNode)
{
printf("AddWord2Hash:Insufficient Memory!\n");
exit(0);
}
/* 保证存放单词的内存是4-byte的整数倍,且末尾为'\0' */
buffLen = (strlen(word)/sizeof(int) + 1) * sizeof(int);
pNewNode->word = (char *)malloc(buffLen);
if (NULL == pNewNode->word)
{
free(pNewNode);
printf("AddWord2Hash:Insufficient Memory!\n");
exit(0);
}
memset(pNewNode->word, 0, buffLen);
pNewNode->prev = NULL;
pNewNode->next = NULL;
pNewNode->count = 1;
strcpy(pNewNode->word, word);
if (NULL == table[idx].head) // idx处冲突链为空
{
table[idx].head = pNewNode;
table[idx].tail = pNewNode;
(table[idx].length)++;
}
else // idx处冲突链非空
{
pTmpNode = table[idx].head;
while (pTmpNode != NULL)
{
if (strcmp(word, pTmpNode->word) > 0) // 比较结果大于0,继续循环
{
pTmpNode = pTmpNode->next;
}
else if (0 == strcmp(word, pTmpNode->word)) // 若单词重复,计算值加1,不执行插入
{
(pTmpNode->count)++;
free(pNewNode);
return;
}
else // 找到插入位置
{
if (NULL == pTmpNode->prev) // 插在冲突链首结点位置
{
table[idx].head = pNewNode;
}
else // 插在冲突链中间节点位置
{
pTmpNode->prev->next = pNewNode;
pNewNode->prev = pTmpNode->prev;
}
pNewNode->next = pTmpNode;
pTmpNode->prev = pNewNode;
(table[idx].length)++;
return;
}
}
if (NULL == pTmpNode) // 插在冲突链尾节点位置
{
(table[idx].tail)->next = pNewNode;
pNewNode->prev = table[idx].tail;
table[idx].tail = pNewNode;
(table[idx].length)++;
}
}
}
/* hash缓存释放函数,从冲突链头开始释放;hash表为栈内存,由系统自动释放 */
void FreeHash(dList_t *table)
{
unsigned int idx = 0;
dNode_t *pTmpNode = NULL;
if (NULL == table)
{
printf("FreeHash:Insufficient Memory!\n");
exit(0);
}
for (idx = 0; idx < HASH_SIZE; idx++)
{
table[idx].length = 0;
pTmpNode = table[idx].head;
while (pTmpNode != NULL)
{
table[idx].head = pTmpNode->next; // 记录新的冲突链头
if (pTmpNode->next != NULL)
{
pTmpNode->next->prev = NULL;
}
free(pTmpNode->word);
free(pTmpNode);
pTmpNode = table[idx].head;
}
}
}
/* 打印函数:文件打印 */
void PrintFunc(dList_t *table)
{
FILE *fp = NULL;
unsigned int idx = 0;
dNode_t *pTmpNode = NULL;
if (NULL == table)
{
printf("PrintFunc:Insufficient Memory/Table isnot Existing!\n");
exit(0);
}
fp = fopen("Stat_result.txt", "w");
if (NULL == fp)
{
printf("PrintFunc:Cannot Creat a file!\n");
exit(0);
}
fprintf(fp, "==== STAT. RESULTS ====\n\n");
fprintf(fp, "Total Words: %6d\n", g_StatResult[LETTER]);
fprintf(fp, "Total Puncts: %6d\n", g_StatResult[COMM_PUNCT]);
fprintf(fp, "Total Number: %6d\n", g_StatResult[NUMBER]);
fprintf(fp, "Total DbChar: %6d\n", g_StatResult[DOUBLE_CHAR]);
fprintf(fp, "Total Other: %6d\n", g_StatResult[OTH_VISI_CHAR]);
fprintf(fp, "\n\n======== WORD LIST ========\n");
fprintf(fp, "\nWORD FREQUENCY\n\n");
for (idx = 0; idx < HASH_SIZE; idx++)
{
pTmpNode = table[idx].head;
while (pTmpNode != NULL)
{
fprintf(fp, "%-20s%2d\n", pTmpNode->word, pTmpNode->count);
pTmpNode = pTmpNode->next;
}
if (table[idx].head != NULL)
{
fprintf(fp, "\n");
}
}
fprintf(fp, "========= THE END =========\n");
fclose(fp);
}
/* hash函数,取单词的首字母与字符a的差值为hash表的索引值 */
unsigned int HashFunc(char *key)
{
unsigned int idx = 0;
if (NULL == key)
{
printf("HashFunc:Insufficient Memory!\n");
exit(0);
}
idx = (int)(*key - 'a');
return idx;
}
相关文章推荐
- 每天一个小程序之python实现统计英文单词出现个数
- 每天一个小程序——第 0004 题:任一个英文的纯文本文件,统计其中的单词出现的个数
- 每天一个python小程序 004:任一个英文的纯文本文件,统计其中的单词出现的个数
- 软件体系结构课程设计:词频统计程序(包含英文单词和数字double,int)
- 输入一段英文文本,用程序统计出现频率最高和最低的两个单词;
- Java 文件统计:编写程序,统计英文文本文件中的字符数目和单词数目。程序运行时,输入要统计的文件的名称,程序处理后输出字符数目和单词数目
- C++英文单词统计小程序
- 一个利用map统计一段英文文章中每个单词出现次数的小程序
- 实现一个控制台程序,给定一段英文字符串,统计其中各个英文单词(4字符以上含4字符)的出现频率。
- 布同 统计英文单词的个数的python代码
- 统计一篇英文文件中,单词出现的次数,并按单词的长度进行排序
- 意外收获-ruby编写的一个简单统计单词出现次数的程序
- 布同:统计英文单词的个数
- 练习2-4:编一个程序统计文件中特定单词出现的次数(要求使用string类的运算符==来查找单词) .
- 英文单词个数统计(从多到少排序)
- C++经典题目二:统计一篇英文文章中的单词个数
- 单词统计程序
- F# 统计一段英文文章中不同单词出现的次数
- 《C++ Primer》学习笔记:map容器insert操作的使用——编写程序统计并输出所读入的单词出现的次数
- 用STL解决单词统计程序