英文单词统计程序

本文使用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;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值