您的位置:首页 > 理论基础 > 数据结构算法

英文单词统计程序

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;

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C语言 hash 数据结构
相关文章推荐