이전에 작성한 코드: (1) C 언어로 된 큰 숙제를 위한 단어 빈도 통계 프로그램

        나는 이미 졸업했고, 프로그래밍 관련 일을 한 적이 없으며, 앞으로 코드를 거의 작성하지 않을 것입니다. A+B의 맨 처음부터 매우 멋져 보이는 모든 종류의 프로그램에 이르기까지 수년에 걸쳐 많은 코드를 작성하는 것에 대해 생각해 보십시오. 많은 함정을 밟고, 많은 사람에게 물어보고, 많은 정보를 확인했습니다. 지금까지 감히 C언어에 능통하다고 말하지만, 언어 자체에 능숙할 뿐이고, 아직까지 다양한 전문 분야의 알고리즘에 대해서는 거의 알지 못합니다. 할 일 없을 때 컴퓨터 디스크를 정리하다 보면 신입생부터 대학원생 단계까지 쓰여진 다양한 프로그램들이 많이 발견되는데 그걸 지울 생각을 하니 안타깝고 결국 몇 년의 공들인 노력이다. . 일이 바쁘지 않을 때 이전 코드를 공개하는 것은 어떨까, 한편으로는 기념품으로, 앞으로는 수십만 줄의 코드를 작성했다고 자랑할 수 있으므로 증명할 수 있습니다. 한편, 후발자에 대한 참고 자료도 제공되며, 그들을 돕는 것도 좋습니다.

소스 코드를 보려면 여기를 클릭하십시오.

단어 빈도 통계 프로그램

1. 주제 요건

        C 언어로 간단한 단어 빈도 통계 프로그램을 작성하기 위한 요구 사항은 다음과 같습니다.

1. 파일에서 영문 짧은 문단을 읽어 콘솔에 그대로 출력한다.

2. 영어 문장의 다양한 단어 수를 세어 콘솔에 출력합니다.

3. 숫자가 가장 큰 상위 10개 단어를 출력합니다.

2. 주제 분석

      주제의 요구 사항으로 판단하면 몇 가지 프로그래밍 기술을 사용해야 합니다. 첫째, 파일에서 데이터를 읽는 것은 파일 작업, 둘째, 영어 단락을 저장하기 위해서는 배열, 셋째, 길이가 다른 단어를 저장하려면 메모리의 동적 할당, 넷째, 단어를 읽으려면, 단어 빈도 계산 연결 목록 및 문자열 연산을 포함하고, 다섯째, 빈도가 높은 단어를 출력하려면 정렬을 포함합니다.

3. 구조 및 함수 선언

(1) 구조체 선언

//单词节点
struct WordNode
{
    char* word;//保存单词的字符串
    int count;//该单词的数目
    WordNode* next;//下一个单词节点
};

//单词链表
struct WordList
{
   WordNode* first;//单词链表的首节点
   WordNode* last;//单词链表的末节点
   int nodeCount; //单词节点的数目
};

(2) 함수 선언

a. 커스텀 기능

       이 프로그램의 사용자 지정 기능은 다음과 같습니다.

//打印词汇表,max_num为打印词汇的个数,如果是-1,则全部打印
void PrintWordList(WordList* wordlist, int max_num = -1);

//词汇表排序,isAscend=true为升序排序,否则为降序排序
void SortWordList(WordList* wordlist, bool isAscend = true);

//从词汇表中查找某个词汇,word为要查找的词汇,如果词汇存在表中,则返回该词汇的节点指针,否则返回NULL
WordNode* FindWord(WordList* wordlist, const char* word);

//从文件中读取字符,并保存到字符串中,words为接收字符串地址,count指定读取字符的最大数量,返回值为实际读取的字符个数
int ReadWordsFromFile(FILE* fp, char* words, int count);

//词汇统计,words为已经保存了词汇的字符串,wordlist为将要生成的词汇表,flag如果为true则表示区分大小写,为false则不区分大小写。
void WordsStatistic(const char* words, WordList* wordlist,bool flag);

//从字符串中读取一个单词,start为源字符串words的开始位置下标,end用来接收读取一个单词后,words的下标。返回值为单词的长度,如果返回-1,表示已经读完所有的单词。
int ReadWordFromString(const char* words, int start, int* end, char* word);

//释放词汇表的内存空间
void FreeWordList(WordList wordlist);

b. 라이브러리 기능

       프로그램 자체에서 사용하는 라이브러리 함수는 다음과 같습니다.

//打开文件
FILE* fopen(char const* _FileName, char const* _Mode);
//设置文件指针位置
int fseek(FILE* _Stream,long  _Offset,int  _Origin);
//获取文件指针的位置(计算文件的大小)
long ftell(FILE* _Stream);
//从文件中读取字节
int fread(void*  _Buffer,int _ElementSize,int _ElementCount,FILE*  _Stream);
//动态分配内存
void*  malloc(int _Size);
//获取字符串的长度
int strlen(char const* _Str);
//将字符串复制到另一个字符串
char strcpy(char* _Destination,const char* _Source);
//两个字符串比较
int strcmp(const char* str1,const char* str2);
//关闭文件
int fclose(FILE *Stream);
//释放内存空间
void free(void* block);
//将数据打印到控制台
int printf(const char* format,...);

4. 필요한 헤더 파일에는 다음이 포함됩니다.

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

5. 사용자 지정 기능에 대한 설계 지침

(1), ReadWordsFromFile

            이 기능의 기능은 파일의 영문 기사를 그대로 메모리로 읽어들이는 것입니다.

//从文件中读取若干字节的单词。
//fp:非空的文件指针
//words:用来接收来自文件的字符串
//count:从文件中读取的字节数,如果该参数大于文件实际的字节数,则去取全部的字节
int ReadWordsFromFile(FILE* fp, char* words, int count)
{
    //获取文件的字节数
    fseek(fp, 0, SEEK_END);
    int file_size = ftell(fp);

    //开始读取字符
    fseek(fp, 0, SEEK_SET);
    int buffer_len = count;
    if (count > file_size)buffer_len = file_size;
    for (int i = 0; i < buffer_len; i++)
    {
        char ch;
        fread(&ch, 1, 1, fp);
        words[i] = ch;
    }
    //字符串结尾
    words[buffer_len] = '\0';
    return buffer_len;
}

(2), ReadWordFromString

           전체 영어 단락을 포함하는 문자열에서 단어를 읽습니다.

//从字符串中读取一个单词,因为每次只能读取一个单词,所以为了能够遍历整个字符串,读取完一个
//单词之后,就返回当前的指针位置,下次读取一个单词,指针就从此开始。(类似于文件的读取)
//words:包含英文段落的字符串
//start:从字符串的这个位置开始读取一个单词
//end:接收返回的指针位置
//word:j接收读到的单词
//返回值:返回读到的单词的长度,-1表示已经到了结尾,0表示没有读取到单词
int ReadWordFromString(const char* words, int start, int* end, char* word)
{
    char ch;
    int count = 0;//单词的长度

    *end = start;
    while (true)
    {
        ch = words[*end];
        (*end)++;
        if ((ch >= 48 && ch <= 57) || (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))//如果是谁或者字母,则读取为单词的一部分
        {
            word[count] = ch;
            count++;
        }
        else if (ch == '\0') return -1;//如果读到字符串末尾,则返回结束标志-1
        else break;//如果字符是标点、空格、换行等非字母和数字型字符,则中断,表示已经完成一个单词的读取
    }
    word[count] = '\0';
    return count;
}

(3)、FindWord

           단어 목록에서 지정된 단어를 찾습니다.

//从单词列表中查找单词,如果找到指定的单词,则返回该单词的节点指针,否则返回NULL
//wordlist:单词链表
//word:要查找的单词
WordNode* FindWord(WordList* wordlist, const char* word)
{

    int count = wordlist->nodeCount;
    WordNode* node = wordlist->fisrt;
    //笨办法,遍历整个链表,查找是否存在指定的单词
    for (int i = 0; i < count; i++)
    {
        if (strcmp(word, node->word) == 0)return node;
        node = node->next;
    }

    return NULL;
}

(4) 워드통계

          각 단어의 수를 세고 연결된 목록의 단어를 연결합니다.


//统计单词并生成单词列表
//words:保存英语段落的字符串
//wordlist:一个空的单词列表
//flag:指示是否区分大小写,如果为true,就是区分大小写,false就是不区分大小写
void WordsStatistic(const char* words, WordList* wordlist,bool flag )
{
    int start = 0, end;
    while (true)
    {
        char word[100] = { '\0' };//一般没有单词超过100个字母的吧,所以定义100字节的数组足够了
        int word_len;
        word_len = ReadWordFromString(words, start, &end, word);//从字符串中读取一个单词
        start = end;
        if (word_len == -1)break;//字符串已经到了结尾,表示段落已经处理完,可以停止读取单词
        if (word_len == 0)continue;//没有读取到单词,则立即再次读取
        
        //不区分大小写的话(Is 和is被认为是同一个单词),则将单词全部变为小写(如Is变为is)
        if (flag==false)for (int i = 0; i < word_len; i++)
        {
            if (word[i] >= 65 && word[i] <= 90)word[i] = word[i] + (char)32;
        }
      
        WordNode* node;
        node = FindWord(wordlist, word);//读取到一个单词,首先找找这个单词是否在单词链表中,如果在则返回该单词的节点指针
        if (node == NULL)//如果单词链表中不存在该单词,则将该单词添加进去链表中
        {
            WordNode* word_node = (WordNode*)malloc(sizeof(WordNode));//创建一个单词节点
            int word_len = strlen(word);
            word_node->word = (char*)malloc(word_len + 1);//为单词节点的word成员分配空间
            word_node->word[word_len] = '\0';
            word_node->count = 1;
            strcpy(word_node->word, word);//将单词复制到单词节点中
            word_node->next = NULL;

            if (wordlist->fisrt == NULL)//如果单词链表为空,则进行以下操作
            {
                wordlist->nodeCount = 1;
                wordlist->fisrt = word_node;
                wordlist->last = word_node;
            }
            else//单词列表部位空,则进行以下操作
            {
                wordlist->last->next = word_node;
                wordlist->last = word_node;
                wordlist->nodeCount++;
            }
        }
        else//如果单词已经存在单词列表中,则将该单词的数目加1
        {
            node->count++;
        }
    }
}

(5)、PrintWordList

       단어 목록 인쇄

//打印单词列表的前
//wordlist:单词列表
//max_num:打印单词节点的最大数量,如果是-1,则表示打印整个单词链表,如果max_num大于链表的实际长度,也打印全部链表节点。
void PrintWordList(WordList* wordlist, int max_num)
{
    WordNode* node = wordlist->fisrt;
    int n = max_num;
    if (max_num == -1 || max_num > wordlist->nodeCount)n = wordlist->nodeCount;
    //遍历链表并打印
    for (int i = 0; i < n; i++)
    {
        printf("%s:%d\n", node->word, node->count);
        node = node->next;
    }
}

(6) SortWordList

        연결된 단어 목록 정렬

//单词链表排序。冒泡排序,考虑到WordNode的成员数比较少,直接采用值交换的方法,而不是链表节点指针的交换
//wordlist:单词链表
//isAscend:是否升序排序,true为升序排序,false为降序排序
void SortWordList(WordList* wordlist, bool isAscend)
{
    WordNode* p;

    if (wordlist->nodeCount <= 1)return;//如果单词链表的长度小于1则直接结束排序

    for (int i = wordlist->nodeCount - 1; i > 0; i--)
    {
        p = wordlist->fisrt;
        for (int j = 0; j < i; j++)
        {
            if ((isAscend && p->count > p->next->count) || (!isAscend && p->count < p->next->count))
            {
                char* s;
                int c;
                s = p->word;
                c = p->count;
                p->word = p->next->word;
                p->count = p->next->count;
                p->next->word = s;
                p->next->count = c;
            }
            p = p->next;
        }
    }

}

(7)FreeWordList

         단어 목록의 메모리 공간 해제

//释放单词列表
void FreeWordList(WordList wordlist)
{
    WordNode* cur, * next;
    cur = wordlist.fisrt;
    for (int i = 0; i < wordlist.nodeCount; i++)
    {
        next = cur->next;
        free(cur->word);//释放word成员指向的内存
        free(cur);//释放节点的内存
        cur = next;
    }
}

(8)메인

        주요 기능은 파일을 열고, 파일을 가져오고, 단어를 세고, 단어 목록을 정렬하고, 단어 목록을 인쇄하는 것입니다.

int main()
{
    char* words;
    FILE* fp;
    fp = fopen("test.txt", "r");

    //获取文件的字节数
    int file_size;
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);

    //重置文件指针到开头
    fseek(fp, 0, SEEK_SET);

    //从文件中读取单词到字符串
    words = (char*)malloc(file_size + 1);
    ReadWordsFromFile(fp, words, file_size);

    //打印原文 
    printf("原文:\n");
    printf("%s\n", words);

    //单词频率统计,不区分大小写
    WordList wordlist;
    wordlist.fisrt = NULL;
    wordlist.last = NULL;
    wordlist.nodeCount = 0;
    WordsStatistic(words, &wordlist,false);//false表示不区分大小写

    //打印词汇列表,全部打印
    printf("词频统计表:\n");
    PrintWordList(&wordlist,-1);//-1位打印全部链表节点

    //词汇表排序,降序排序
    SortWordList(&wordlist,false);//false表示降序排序

    //打印频率最高的10个单词
    printf("高频词汇:\n");
    PrintWordList(&wordlist,10);

    fclose(fp);
    free(words);
    FreeWordList(wordlist);
    getchar();
    return 0;
}

(6) 동작 효과 표시

Supongo que te gusta

Origin blog.csdn.net/qq_28249373/article/details/103929986
Recomendado
Clasificación