用hash表统计文本文件中每个单词出现的频率

闲来无事,敲两行代码解解愁。

今天介绍一种用自已建立的hash表(hash链表)来统计一个输入文本文件中每个单词出现的频率,hash表的构造详见《编程珠玑》第15章。

一、主体思路:

 

  (1)建立一个hash表;

    --(a) hash函数:除留取余法,H(key) = key % size;

    --(b) 解决冲突的方法:链地址法,将所有映射到相同索引的字符串用链接指针连接在一起。

  (2)读取文本文件word.txt,每次读取一行,然后分隔每个单词,插入到hash表,插入过程中会对单词出现次数统计;

  (3)将整个hash表内容写到一个文本文件result.txt中。

 

二、数据结构及算法实现

  (1)hash表

   --(a) hash表大小(HASHNUMBER):采用一个大质数作为表的总容量,本例中为HASHNUMBER29989;

     #define HASHNUMBER 29989 //散列表的大小,29989为质数。
       #define MULT 31 //hash函数的一个乘子。

        typedef struct hashnode

        {//链表中每个节点的结构
           hashnode()
           {
              word = NULL;
              count = 0;
              next = NULL;
           }
           char * word;//单词
           int count;//出现频率
           struct hashnode *next;//指向链表中具有相同hash值的下个节点
       }hashNode,*hashNodePtr ;

      hashNodePtr bin[HASHNUMBER] = { NULL};//HASHNUMBER大小的指针数组 作为hash表。

   --(b) hash函数:将每个单词映射为一个小于HASHNUMBER的正整数;

     unsigned int hashIndex(const char * pWord)//返回hash表索引(即hash指针数组的下标)。
      {
          assert(pWord != NULL);
          unsigned int index = 0; //以下四行为将一个单词映射到一个小于HASHNUMBER的正整数的函数。
           for(;*pWord != '/0';pWord++)
               index = MULT * index + *pWord;
           return index % HASHNUMBER;

      }

   --(c) 向hash表中插入单词。

  void insertWord (const char * pWord )// hash 表中插入单词,如果已经存在了,则增加单词的出现次数count

  {

    assert (pWord != NULL );

    hashNodePtr p ;

    unsigned int index = hashIndex (pWord );//用(b)中的hash函数得到单词在hash表中的下标。

    for (p =bin [index ];p != NULL ;p = p ->next )

    {// 查找是否单词已经在hash 表中了。

       if (strcmp (pWord ,p ->word ) == 0)

       {// 找到,将单词出现次数加.

           (p ->count )++;

           return ;

       }

     }

    p = (hashNodePtr )malloc (sizeof (hashNode ));//hash 表中不存在该单词,创建节点。

    p ->count = 1;//出现次数设置为1。

    p ->word = (char *)malloc (strlen (pWord )+1);

    strcpy (p ->word ,pWord );

    p ->next = bin [index ];//将新生成的节点插入到index为下标的链表中去。

    bin [index ] = p ;

 }


  (2)读取Data.txt中的单词,并将每个单词插入到(1)中设计好的hash表中。

   void readWordToHashTable (const char *path )

   {// 从文本文件中读取单词,插入到hash 表中。

      FILE *fp ;

      char buf [1024];// 存储一行字符串。

      char *p ;

      fp = fopen (path ,"r" );

      if (fp == NULL )

      {

         printf ("open file error!exit/n" );

         exit (-1);

      }

      while (NULL != fgets (buf ,sizeof (buf ),fp ))//数据读完,到文本末尾了

      {

         buf [strlen (buf )-1] = '/0' ; // 除去单词最后的换行符

         //printf("%s/n",buf);

         if (strcmp ("" ,buf )==0)//blank line,continue.

           continue ;

         p = strtok (buf ,"'/t',' ','/n'" );//用strtok函数从一行字符串中分离出每个单词,分隔符设置为(空格、逗号、换行、制表符)。

         while (p != NULL )

         {

           insertWord (p );// 调用insertWord(),向hash 表中插入分隔出来的单词。

           p = strtok (NULL ,"'/t',' ','/n'" );

         }

       }

        fclose (fp );

   }


    (3) 将hash表中对每个单词的统计信息写入到文本文件中。

    void writeHashTable (const char *path )

    {// 将结果写到path 中。

      FILE *fp

      hashNodePtr p ;

      int i ;

      fp = fopen (path ,"w" );

      if (fp == NULL )

      {

         printf ("write file error! exit" );

         exit (-1);

      }

      for (i =0;i <HASHNUMBER ;i ++)

      {

         for (p = bin [i ];p != NULL ;p = p ->next )

         {

             fprintf (fp ,"Index %d: <%s,%d>" ,i ,p ->word ,p ->count );

             if (p ->next == NULL )

                fprintf (fp ,"/n" );

         }     

      }

      fclose (fp );

  }

 

(4)释放hash表中占用的内存

void freeHashTable()//释放hash表所占用内存。
  {
    int i;
    hashNodePtr p,q;
    p = q = NULL;
    for(i=0;i<HASHNUMBER;i++)
    {
        p = bin[i];
        while(p != NULL)
        {
            q = p;
            p = p->next;
            free(q->word);
            free(q);
        }
     }
  }

(5) main函数中。

    int main (void )

    {

      readWordToHashTable ("data.txt" );

      writeHashTable ("result.txt" );

      return 0;

  }

展开阅读全文

没有更多推荐了,返回首页