课堂练习 · 写一个程序,分析一个一篇英文文章中各个单词出现的频率,并且把频率最高的10词打印出来。

分解题目,决定用C语言编写:

       1.打开任意英文文本文件;

       2.识别每个单词;

       3.计算出现频率最高的十个单词,并打印出来。

 

 

首先确定保存单词和它们出现的次数,记录单词种类数和单词总数的结构体:

     识别单词时,分为四种情况:读出的字符是

                                            1.单词开始的第一个字符

                                            2.单词结尾

                                            3.单词中间部分

                                            4.非单词符号,如空格,’.‘,’,‘ ······一视同仁,过滤

typedef struct 
{
    char letter[SizeWord];   
    long amount;
}Word;
typedef struct 
{
    Word words[NumWords];
    long type;
    long count;
}WordStatistics;

从文件中读出字符并识别每个单词,记录单词数量:

    wordlist->count=0;
    wordlist->type=0;
    start=0;   \\标志一个单词的开始
    for(i=0;i<SizeWord;i++)
        w[i]='\0';
    while(!feof(lp))
    {    
        ch=fgetc(lp);
        if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')||(ch=='-')||(ch==39))    \\分析可能出现的情况,如:Tom`s、five-year-old等
        {
            if(start==0)    \\单词的开始字符出现
            {
                start=1;
                wordlist->count++;
                i=0;
                w[i]=ch;
            }
            else           \\单词中间部分
            {
                if(i<SizeWord)
                    w[++i]=ch;
                else
                {
                    printf("单词数组溢出!");
                    exit(0);
                }
            }
        }
        else
        {
            if(start=1)         \\一个单词结束
            {
                start=0;
                w[++i]='\0';
                Compareword(wordlist,w);  
                for(i=0;i<SizeWord;i++)
                    w[i]='\0';
            }
            else               \\不会在一个单词中出现的字符,过滤
                continue;
        }
    }

将识别的单词记录在结构体数组中:

void Compareword(WordStatistics *wordlist,char w[])
{
    long j;
    int flag=0;      //将该单词与已经出现并记录的单词进行比对
    for(j=0;j<wordlist->type;j++)
    {
        if(strcmp(wordlist->words[j].letter,w)==0)
        {
            wordlist->words[j].amount++;     //计算单词出现次数
            flag=1;
            break;
        }
    }
    if(flag==0)     //出现新单词
    {
        strcpy(wordlist->words[wordlist->type].letter,w);
        wordlist->words[wordlist->type].amount=1;
        wordlist->type++;
    }
}

找出文章中出现频率最高的10个单词:

     在这部分程序的编写中出现了很多问题,

           1.如果对全部的单词进行排序,会花费较大的代价,但除了出现频率最高的10个单词,其他单词的排序都没有用。

           2.先挑选出10个出现频率最高的单词,再进行排序。但是这10个单词怎么挑选哪?比如5个单词中选三个,如1,4,3,5,6,将前三个作为样本,不考虑他们的顺序,只要有比前三个数大的就交换,可能得到的是6,4,3,显然结果是错误的,只好边排序(前10个),边比较,梳理单词的顺序。(突然发现如果结构体存储为链表形式比较简单。额--|||)

           3.(升级版)每次比较都找出前10个单词中出现次数最小的一个,跟第10个单词之后的单词比较,如果比最小的单词大,替换最小单词。最后将找出的10个单词进行排序。单词位置的交换次数就少了很多。

           如果你看到这里,那么我想问,在这样的情况下,用什么样的方法更有效?

           (三种方法的计算速度还需之后的实验证明,本次程序采用第二种方法选择文章中出现频率最高的单词。)

void SelectTopwords(WordStatistics *wordlist)//
{
    void SortWord(Word *topwords,int count);
    Word topwords[Toprate];
    int i,j,k,n;
    Word temp;
    float num;
    k=wordlist->type>Toprate?Toprate:wordlist->type;
    for(i=0;i<k;i++)
    {
        strcpy(topwords[i].letter,wordlist->words[i].letter);
        topwords[i].amount=wordlist->words[i].amount;
    }
    for(j=0;j<k;j++)
    {
        for(i=0;i<k-j;i++)
            if(topwords[i].amount>topwords[i+1].amount)
            {
                strcpy(temp.letter,topwords[i].letter);
                temp.amount=topwords[i].amount;
                strcpy(topwords[i].letter,topwords[i+1].letter);
                topwords[i].amount=topwords[i+1].amount;
                strcpy(topwords[i+1].letter,temp.letter);
                topwords[i+1].amount=temp.amount;
            }
    }
    if(wordlist->type>Toprate)
    {
         for(j=Toprate;j<wordlist->type;j++)
               for(i=0;i<Toprate;i++)
                if(wordlist->words[j].letter>wordlist->words[i].letter)
                {
                    for(n=Toprate-1;n>i;n++)
                    {
                        strcpy(topwords[n].letter,wordlist->words[n-1].letter);
                        topwords[n].amount=wordlist->words[n-1].amount;
                    }
                    strcpy(topwords[i].letter,wordlist->words[j].letter);
                       topwords[i].amount=wordlist->words[i].amount;
                    break;
                }
    }
    printf("             出现频率最高的10个单词");
    printf("\n______________________________________________________\n");
    for(i=0;i<k;i++)
    {
        num=(float)wordlist->words[i].amount/k*100;
        printf("\n\t%s\t\t%3.2f\n",wordlist->words[i].letter,num);
    }
    printf("\n______________________________________________________\n");
}

最后总结,在编写程序时花费时间最长的地方在选择排序的方法,文件路径的输入方法,还有结构体数组,结构体指针作为函数参数的使用(尤其是他),越改越晕,还需请大师指教T T。

 

 

posted @ 2014-03-02 21:04  安娜123  阅读(658)  评论(1编辑  收藏  举报