zoukankan      html  css  js  c++  java
  • 课堂练习 · 写一个程序,分析一个一篇英文文章中各个单词出现的频率,并且把频率最高的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]='';
        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]='';
                    Compareword(wordlist,w);  
                    for(i=0;i<SizeWord;i++)
                        w[i]='';
                }
                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("
    ______________________________________________________
    ");
        for(i=0;i<k;i++)
        {
            num=(float)wordlist->words[i].amount/k*100;
            printf("
    	%s		%3.2f
    ",wordlist->words[i].letter,num);
        }
        printf("
    ______________________________________________________
    ");
    }

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

  • 相关阅读:
    Redis "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk"问题的解决
    素描
    python 标准库
    Python内置函数filter, map, reduce
    Python的lambda表达式
    python中super关键字的用法
    python一个注意的地方
    python中self,cls
    python中的实例方法、静态方法、类方法、类变量和实例变量
    python模块及包的导入
  • 原文地址:https://www.cnblogs.com/anna123/p/3577282.html
Copyright © 2011-2022 走看看