分析一个文本文件(英文文章)中各个词出现的频率,并且把频率最高的10个词打印出来
第一次这样交作业,好不习惯,废话不多说,上代码及整个分析编写过程。
这次的程序大约花费了不到4个小时(2课时+一晚上),整体的设计思想是分三部分:从文件读入并分析收集单词,统计单词的频率,排序输出。下面是具体实现过程:
- 建立一个哈希表结构体Hash_table和一个单词缓存区buffer并分别对其做初始化
typedef struct Hash{ int count; char str[20]; }Hash_table;
初始化:
void initial_buffer () { for (tail_prob = 0; tail_prob < MAXWORD ;tail_prob++) { buffer[tail_prob++] = '\0'; } tail_prob = 0; } void initial_hashtable () {while (i < hashnum) { hash_table[i].count = 0; i++; } }
2. 统计文件中单词出现的频率,将单词及其频率存储在哈希表中
void find_frquence(FILE *in,FILE *out) {do { if (character >0x20 && character < 0x80) { if (flag==1) { copytobuffer (character); } else //新单词,且是字母和数字的组合*/ { if(find_match())
{ }
else { addtoHash (); Hcount++; } copytobuffer (character); flag = !flag; } } else { if (character <= 0x20 || character >= 0x80) { if (flag) { buffer[tail_prob] = '/0'; if (find_match) /*如果能够找到,则对应的频率加1,find_match实现频率加1*/ { } else /*不能找到,则到哈希表中*/ { addtoHash (); Hcount++; } copytobuffer (character); flag = !flag; } else { copytobuffer (character); } } } }while ((character = fgetc (in)) != EOF); /*处理最后缓冲区所存储的单词*/ if(find_match()) { } else { addtoHash(); Hcount++; } }
3.使用除留余数法查询哈希表中的单词,若存在则频率+1
int find_match () {while (hash_table[index].count) { if (len1 == len2) //些比较len1和len2是否相等,如果不等再比较 { for (i = 0;i<len1 && *str == *temp;i++) { str++; temp++; } if (i != len2) { index = (index + 1) % hashnum; temp = hash_table[index].str; str = buffer; return -1; } else //能找到 { hash_table[index].count++; return TURE; } } else { index = (index + 1) % hashnum; temp = hash_table[index].str; str = buffer; return -1; } } }
4.排序后输出到一个文件中,也可输出在屏幕上
void Hash_sort(FILE *out) { while (i < Hcount) { /*找到第一个遇见的频率非零的结点*/ while (hash_table[index].count == 0) { index ++; } symbol = hash_table[index].count; /*充当最大值*/ num = index; index++; while (index < hashnum) { if (symbol < hash_table[index].count && hash_table[index].count) { symbol = hash_table[index].count; num = index; } index ++; } len = strlen (hash_table[num].str); //printf("%d\t",hash_table[num].count); //printf("%s\n",hash_table[num].str); fprintf(out,"%s,%d\n",hash_table[num].str,hash_table[num].count); hash_table[num].count = 0; i++; index = 0; } }
5.源代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define FOOL int #define TURE 1 #define FALSE 0 #define MAXWORD 20 #define hashnum 1024 /*采用哈希表结点结构*/ typedef struct Hash{ int count; char str[20]; /*不一定为1,而是动态分配*/ }Hash_table; Hash_table hash_table[hashnum]; char buffer[256]; /*缓冲区大小,用来暂时存储单词*/ int tail_prob; /*缓冲区结束位指针 */ int Hcount = 0; /*用来计算有多少单词*/ /******************************************************************/ /** 初始化操作 **/ /** **/ void initial_buffer () { for (tail_prob = 0; tail_prob < MAXWORD ;tail_prob++) { buffer[tail_prob++] = '\0'; } tail_prob = 0; } void initial_hashtable () { unsigned int i; i = 0; while (i < hashnum) { hash_table[i].count = 0; i++; } } /******************************************************************/ /** 关于缓冲区的操作 **/ /** **/ /*把一个字符拷贝到缓存区中*/ void copytobuffer (char character) { if (tail_prob >= MAXWORD) { printf("Usag:this word is too long!"); exit (-1); } buffer[tail_prob++] = character; } /*清除缓冲区*/ void clear_buffer () { while (tail_prob != 0) { buffer[--tail_prob] = '\0'; } } /**************************************************************/ /** 找哈希表的关键字,这里使用的是把字符串的值相加再求与哈希表**/ /**长度的余 **/ unsigned int get_key (char *str) { unsigned result = 0; do { result = result + (*str); str++; }while (*str != NULL); result = result % hashnum; return result; } /***************************************************************/ /**看哈希表中是否有对应的单词,有返回真 **/ /** **/ int find_match () { int i; char *str; char *temp; int len1; /*缓冲区中单词的长度*/ int len2; /*哈希表中单词的长度*/ int index; str = buffer; index = get_key (buffer); temp = hash_table[index].str; len1 = strlen (buffer); len2 = strlen (temp); while (hash_table[index].count) { if (len1 == len2) /*些比较len1和len2是否相等,如果不等再比较*/ { for (i = 0;i<len1 && *str == *temp;i++) { str++; temp++; } if (i != len2) { index = (index + 1) % hashnum; temp = hash_table[index].str; str = buffer; return -1; } else //能找到 { hash_table[index].count++; return TURE; } } else { index = (index + 1) % hashnum; temp = hash_table[index].str; str = buffer; return -1; } } } /***************************************************************/ /** 根据缓冲区里面的字符生成哈希表 **/ /** **/ void addtoHash() { char str_temp[256]; char *str; char *temp; int len; unsigned int index; int i; i=0; str = str_temp; strcpy (str,buffer); index = get_key (str); len = strlen(str); temp = hash_table[index].str; while (hash_table[index].count) /*找到没有被储存的结点*/ { index = (index + 1) % hashnum; } hash_table[index].count++; while (i < len) /*复制字符串*/ { *temp++ = *str++; i++; } } /***************************************************************/ /** 排序后输出到out文件中 **/ /** **/ void Hash_sort(FILE *out) { int index; unsigned int symbol; /*最大值*/ int num; int len; int i = 0; index = 0; /*排序输出到out文件中,共有Hcount个单词*/ while (i < Hcount) { /*找到第一个遇见的频率非零的结点*/ while (hash_table[index].count == 0) { index ++; } symbol = hash_table[index].count; /*充当最大值*/ num = index; index++; while (index < hashnum) { if (symbol < hash_table[index].count && hash_table[index].count) { symbol = hash_table[index].count; num = index; } index ++; } len = strlen (hash_table[num].str); //printf("%d\t",hash_table[num].count); //printf("%s\n",hash_table[num].str); fprintf(out,"%s,%d\n",hash_table[num].str,hash_table[num].count); hash_table[num].count = 0; i++; index = 0; } } /***************************************************************** /*找文件in中单词出现的频率,存储其单词以及其频率,调用find_match*/ /*输入的字符小于等于Ox20或者大于0x80时说明不是数字或者字母。但是*/ /*也能组成一个单词 */ void find_frquence(FILE *in,FILE *out) { char character; FOOL flag; flag = 1; /*开关语句*/ initial_buffer(); initial_hashtable (); /*当没有到文件结束时*/ character = fgetc (in); do { if (character >0x20 && character < 0x80) { if (flag) { copytobuffer (character); //find_match(); } else /*新单词,且是字母和数字的组合*/ { buffer[tail_prob] = '\0';/*表示结束*/ if(find_match ()) /*如果能够找到,相对应的频率加1*/ { //Tprob->count++; } else /*不能找到,则生成一个新的结点加入孩子兄弟链表中*/ { addtoHash (); Hcount++; } clear_buffer (); copytobuffer (character); flag = !flag; } } else { if (character <= 0x20 || character >= 0x80) { if (flag) { buffer[tail_prob] = '/0'; if (find_match ()) /*如果能够找到,则对应的频率加1,find_match实现频率加1*/ { // Tprob->count++; } else /*不能找到,则到哈希表中*/ { addtoHash (); Hcount++; } clear_buffer (); /*清除缓冲区*/ copytobuffer (character); flag = !flag; } else { copytobuffer (character); } } }// if - else 结束 }while ((character = fgetc (in)) != EOF); /*处理最后缓冲区所存储的单词*/ if(find_match()) { // Tprob->count++; } else { addtoHash(); Hcount++; } /*排序并按从小到大输出到out文件中*/ Hash_sort(out); } /**************************************************************/ void main(int argc,char *argv[]) { FILE *in; FILE *out; char temp_string1[256]; char temp_string2[256]; if((in=fopen("temp_string1.txt","r"))==NULL) { printf("Please input the file you want to compile:\n"); exit(0); } in=fopen("temp_string1.txt","r"); //in = fopen (temp_string1,"r"); out = fopen ("temp_string2.txt","w"); /*找到各个单词,并且存储其频率,按频率顺序排列后输出到out中*/ find_frquence (in,out);
fclose(in); fclose(out); }
6.总结
说实话,自己学的真的很渣,在有了大体思想后就开始从网上各种收集资料,但在编写的过程中还是遇到了很多问题,编译各种不通过,最后在多处求教同学和查资料后,得到了解决。这次的作业体会最深的一点就是,什么事都得靠自己去完成(因为不能类同了)!在这次的作业中,也对fgetc有了很深的了解,同时了解到了字符在16进制中的表示,还有一点就是,对哈希表又重新温习了一次。继续努力学习,望鼓励支持,哈哈