数据结构

文学研究助手

文学研究助手

【问题描述】

统计一篇英文小说中某些形容词出现的次数。

【基本要求】

英文小说存在一篇txt文档中,统计工作一次进行完毕,需要统计的词一次性输入完毕。

【测试数据】

自行设计

【实现提示】

文件名,输入的单向都由

string

储存,因为输入带空行,所以用

getline

函数读入,一次读一行,具体实现方法为字典树,可以理解为弱化的AC自动机,因为不需要其中的fail指针,首先将输入的单词一个个分离出来然后构造一棵字典树,遍历英文小说,每个词放在字典树里面匹配一下,匹配成功就将最后一个字母的数字加一。

【问题分析】

字典树的每个节点为


struct node{
    node *next[26];
    int count;

    node(){
        count = 0;
        memset(next,NULL,sizeof(next));
    }
};

其中

*next[26]

是节点的子节点,构造的时候默认设置成NULL。

创建字典树的函数为


void insert(char* str,node *root){
    int i = 0,index;
    node *p = root;

    while(str[i] != '\0'){
        index = str[i] - 'a';
        if(p->next[index] == NULL)p->next[index] = new node();
        p = p->next[index];
        i++;
    }
}
root

是根节点,根节点不包含任何字母,

i

是传入的字符串的下标,对传入的字符串遍历一下,对于某个节点下一个,如果字符串对应的下一个字母节点为空的话,那么就c创建一个新的节点。否者,直接将指针指向对应的下一个节点。

对应的主函数里面的部分为


 string input;
    node *root = new node();
    map<char*,int> my_word;
    char *cstr = new char[input.length()+1];
    strcpy(cstr,input.c_str());
    char* token = strtok(cstr," ");
    while(token != NULL){
        my_word.insert(pair<char*,int>(token,0));
        insert(token,root);
        token = strtok(NULL," ");
    }

这里需要用到一个

strtok

函数。用来将每个单词分离出来。其中

my_word

用来方便后面的遍历,输出。

读入小说的部分为


void read_file(string file_name,node* root){
    ifstream istr{file_name,ios::binary | ios::ate};
    if(!istr.is_open()){
        cout<<"Failed to open "<<file_name<<endl;
    }else{
        auto size = istr.tellg();
        string file(size,'\0');

        istr.seekg(0);//这儿是回溯
        istr.read(&file[0],size);//将文件读入string中

        char *cstr = new char[file.length()+1];
        strcpy(cstr,file.c_str());

        char *token = strtok(cstr," ");
        while(token != NULL){
            my_compare(token,root);//这个函数用来计数
            token = strtok(NULL," ");
        }
    }
}
void my_compare(char* str,node *root){
    node *p = root;
    int index,i = 0;

    while(str[i] != '\0'){
        index = str[i] - 'a';
        if(p->next[index]  == NULL)return;
        else p = p->next[index];
        i++;
    }

    p->count+=1;
}

用来计数的

my_compare

函数具体是遍历,然后每个对比,只有字符串在字典树里面有才会走到字典树的最后节点,并将最后节点的计数数值加一,只要其中一个不一样,就会直接结束比较。

随后主函数里面的遍历输出为


for(map<char*,int>::iterator it = my_word.begin();it != my_word.end();it++){
        it->second = find(it->first,root);
        cout<<"The total number of "<<it->first<<" is "<<it->second<<endl;
    }

最后附上全部代码


#include <iostream>
#include <string.h>
#include <cstdlib>
#include <fstream>
#include <map>

using namespace std;

struct node{
    node *next[26];
    int count;

    node(){
        count = 0;
        memset(next,NULL,sizeof(next));
    }
};

void insert(char* str,node *root){
    int i = 0,index;
    node *p = root;

    while(str[i] != '\0'){
        index = str[i] - 'a';
        if(p->next[index] == NULL)p->next[index] = new node();
        p = p->next[index];
        i++;
    }
}

void my_compare(char* str,node *root){
    node *p = root;
    int index,i = 0;

    while(str[i] != '\0'){
        index = str[i] - 'a';
        if(p->next[index]  == NULL)return;
        else p = p->next[index];
        i++;
    }

    p->count+=1;
}

int find(char* str,node *root){
    node *p = root;
    int index,i = 0;

    while(str[i] != '\0'){
        index = str[i] - 'a';
        p = p->next[index];
        i++;
    }

    return p->count;
}

void read_file(string file_name,node* root){
    ifstream istr{file_name,ios::binary | ios::ate};
    if(!istr.is_open()){
        cout<<"Failed to open "<<file_name<<endl;
    }else{
        auto size = istr.tellg();
        string file(size,'\0');

        istr.seekg(0);
        istr.read(&file[0],size);

        char *cstr = new char[file.length()+1];
        strcpy(cstr,file.c_str());

        char *token = strtok(cstr," ");
        while(token != NULL){
            my_compare(token,root);
            token = strtok(NULL," ");
        }
    }
}

int main(){
    string input;
    string filename;
    map<char*,int> my_word;
    node *root = new node();
   
    cout<<"Please in put your file name"<<endl;
    getline(cin,filename);

    cout<<"input your key words"<<endl;
    getline(cin,input);

    char *cstr = new char[input.length()+1];
    strcpy(cstr,input.c_str());
    char* token = strtok(cstr," ");
    while(token != NULL){
        my_word.insert(pair<char*,int>(token,0));
        insert(token,root);
        token = strtok(NULL," ");
    }

    read_file(filename,root);

    for(map<char*,int>::iterator it = my_word.begin();it != my_word.end();it++){
        it->second = find(it->first,root);
        cout<<"The total number of "<<it->first<<" is "<<it->second<<endl;
    }
}

 

Leave a Reply

邮箱地址不会被公开。 必填项已用*标注