有关统计单词频率的算法c语言实现

从一文本中读取单词,统计其出现的频率,并按频率大小输出到另一文本中。这里的单词是分二种,一种是ASCII码大于0x20小于0X80字符,第 二种是小于0x20以及大于0x80的字符。这里我用的是哈希表,这样能很快查找读取的单词是否已经存在。排序我用的是二个循环,按理来说可以改进。

下面是我的算法。有些地方还需要改进。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define  FOOL     int
#define  TURE      1
#define  FALSE     0
#define  MAXWORD   256
#define  hashnum  1024

/*采用哈希表结点结构*/
typedef struct Hash{ 
    int count;
 char str[1];     /*不一定为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;
   }
   else   //能找到
   {
    hash_table[index].count++;
    return TRUE;
   }
  }
  else
  {
   index = (index + 1) % hashnum;
   temp = hash_table[index].str;
   str = buffer;
  }
 }  
}

/***************************************************************/
/** 根据缓冲区里面的字符生成哈希表                            **/
/**                                                           **/
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 (hash_table[index].count < symbol && hash_table[index].count)
   {
    symbol = hash_table[index].count;
    num = index;
   }
   index ++;
  }
  /*找到了最小值*/
  len = strlen (hash_table[num].str);
  printf("%d ",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);
   }
   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(argc < 2)
 {
  printf ("Usag:please input the correct filename");
  exit (-1);
 }
 if (strlen (argv[1]) >256 || strlen (argv[2]) > 256)
 {
  printf (" Usag:the filename is too long!");
  exit (-1);
 }

 strcpy (temp_string1,argv[1]);
 strcpy (temp_string2,argv[2]);
 in = fopen (temp_string1,"rb");
 out = fopen (temp_string2,"w");

    /*找到各个单词,并且存储其频率,按频率顺序排列后输出到out中*/
 find_frquence (in,out);

 fclose (in);
 fclose (out);
}

 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
贝叶斯算法是一种基于概率的分类算法,可以用于文本分类、垃圾邮件过滤等场景。在C语言中,可以通过以下步骤实现贝叶斯分类算法: 1. 准备训练数据集,包括训练文本和对应的分类标签。 2. 统计每个分类中的单词出现频率,并计算每个单词在每个分类中的出现概率。 3. 对于待分类文本,将其分词并计算每个单词在各个分类中的概率。 4. 根据贝叶斯公式计算该文本属于各个分类的概率,选择概率最大的分类作为预测结果。 下面是一个简单的C语言实现: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_DOC_LEN 1000 //最大文本长度 #define MAX_WORD_CNT 100 //最大单词数 #define MAX_CLASS_CNT 10 //最大分类数 //定义单词结构体 typedef struct{ char word[20]; //单词字符串 int freq; //出现次数 float prob; //出现概率 }Word; //定义分类结构体 typedef struct{ char name[20]; //分类名称 int cnt; //单词数 Word words[MAX_WORD_CNT]; //单词列表 }Class; //全局变量,存储所有分类 Class classes[MAX_CLASS_CNT]; int class_cnt = 0; //统计单词出现次数 void count_words(char *doc, int doc_len, Class *c){ char *p = doc; char word[20] = {0}; int i, j; //遍历文本中的每个字符 for(i=0; i<doc_len; i++){ if(isalpha(p[i])){ //如果是字母 //将字母转换为小写 word[j++] = tolower(p[i]); } else if(j>0){ //如果不是字母但之前有单词 //将单词加入分类中 word[j] = '\0'; for(j=0; j<c->cnt; j++){ if(strcmp(c->words[j].word, word)==0){ c->words[j].freq++; break; } } if(j==c->cnt){ //如果单词不在分类中 strcpy(c->words[j].word, word); c->words[j].freq = 1; c->cnt++; } j = 0; } } } //计算单词出现概率 void calc_probs(Class *c){ int i; int total_words = 0; //统计分类中的总单词数 for(i=0; i<c->cnt; i++){ total_words += c->words[i].freq; } //计算每个单词的出现概率 for(i=0; i<c->cnt; i++){ c->words[i].prob = (float)c->words[i].freq / total_words; } } //训练分类器 void train(char *doc, int doc_len, char *class_name){ int i; Class *c = NULL; //查找分类 for(i=0; i<class_cnt; i++){ if(strcmp(classes[i].name, class_name)==0){ c = &classes[i]; break; } } //如果分类不存在则新建一个分类 if(!c){ strcpy(classes[class_cnt].name, class_name); classes[class_cnt].cnt = 0; c = &classes[class_cnt]; class_cnt++; } //统计单词出现次数 count_words(doc, doc_len, c); //计算单词出现概率 calc_probs(c); } //计算文本在分类中的概率 float calc_doc_prob(char *doc, int doc_len, Class *c){ char *p = doc; char word[20] = {0}; int i, j; float prob = 1.0; //遍历文本中的每个字符 for(i=0; i<doc_len; i++){ if(isalpha(p[i])){ //如果是字母 //将字母转换为小写 word[j++] = tolower(p[i]); } else if(j>0){ //如果不是字母但之前有单词 //查找单词在分类中的出现概率 word[j] = '\0'; for(j=0; j<c->cnt; j++){ if(strcmp(c->words[j].word, word)==0){ prob *= c->words[j].prob; break; } } j = 0; } } return prob; } //预测文本所属分类 char *predict(char *doc, int doc_len){ int i; float max_prob = 0.0; char *class_name = NULL; //遍历所有分类,选择概率最大的分类 for(i=0; i<class_cnt; i++){ float prob = calc_doc_prob(doc, doc_len, &classes[i]); if(prob > max_prob){ max_prob = prob; class_name = classes[i].name; } } return class_name; } int main(){ char doc[MAX_DOC_LEN] = "this is a test document"; char class_name[20] = "test"; //训练分类器 train(doc, strlen(doc), class_name); //预测文本所属分类 char *pred_class = predict(doc, strlen(doc)); printf("Predicted class: %s\n", pred_class); return 0; } ``` 以上代码只是一个简单的示例,实际应用中还需要考虑词频平滑、停用词过滤等问题,以提高分类效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值