杭电acm 2072(单词数)-字典树

思路:
用字典树操作比较快,虽然不用字典树也可以,但是,用一下加深对字典树的理解。而且我的字典树是指针版本的,所以更加有趣。
详细解释看代码注释。

AC code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<set>
using namespace std;//统计文本中不同单词的个数 
const int maxn = 1e4 + 10;//指针操作迷得一批,不过弄对了,说明你掌握了指针这个难点的原理 

struct node{
    int cnt;//cnt可以表示一个字典树到此有多少相同前缀的数目,这里根据需要应当学会自由变化
    node* nex[26];//next是表示每层有多少种类的数,如果只是小写字母,则26即可,
    //若改为大小写字母,则是52,若再加上数字,则是62了,这里根
    bool used;
    node(){//类似于构造函数 
        cnt = 0;
        memset(nex,0,sizeof(nex));
        used = false;//标记是否用过 
    }

}; 
node *root = new node;//新建立一个空间,并把地址给root,作为根结点 

void inseart(string s){
    node* p = root;
    int len = s.size();
    for(int i = 0;i < len;++i){
        if(p->nex[s[i] - 'a'] == NULL){
            //cout << "qq: " << s << endl;
            node* temp = new node;
            p->nex[s[i] - 'a'] = temp;
        }
        p = p->nex[s[i] - 'a'];
        ++p->cnt;
    }
}

int search(string s){
    node* p = root;
    //int len = strlen(s);
    int len = s.size();
    for(int i = 0;i < len;++i){
    //  cout << "pp: " << s << endl;
        if(p->nex[s[i] - 'a'] == NULL){
            return 0;
        }
        p = p->nex[s[i] - 'a'];
        if(i == len -1){//最后一个要特判 

            for(int j = 0;j < 26;++j){//遍历他的子节点,如果还有子节点,说明只是前缀,还要++ans 
                if(p->nex[j] && p->used == false){//用来处理前缀,比如ji,j 
                    p->used = true;//used的标记是为了看前缀出现的次数,出现了的不能再计算 
                    return 0;
                }
            }
        }
    }
    return p->cnt;//
}
void del(node* root){
    /*
    for(int i = 0;i < 10;++i){//这个操作是失败的 
        if(root->nex[i]){
            del(root->nex[i]);
        }
    }
        del(root);
    */
    //delete root;//原来只是释放了根结点的空间,其他的没有释放 
    if(root == NULL){//释放所有空间,防止内存泄露 
        return ;
    }else{
        for(int i = 0;i < 10;++i){//这个操作是失败的 
            if(root->nex[i]){
                del(root->nex[i]);
            }
        }
    }
    delete root;
}
int main(){

    string s,str;
    int flag = 0;
    while(getline(cin , s)){
        if(s == "#"){
            break;
        }
        int ans = 0;
        for(int i = 0;i < s.size();++i){
            str = "";
            flag = 0;
            while(s[i] >= 'a' && s[i] <= 'z'){
                str += s[i];
                flag = 1;
                ++i;
            }
            //cout << "em " << str << endl;
            if(flag == 1){

                if(ans == 0){
                    inseart(str);
                    //first = 0;
                    ++ans;
                }else 
                if(search(str) == 0){//原来不存在 
                    inseart(str);
                    ++ans;
                }
            }
            //cout << "f: " << ans << endl;
        }
        cout << ans << endl;

        del(root);//记得销毁前面的,因为根结点是用一个指针表示的,所以只要销毁指针即可 
        root = new node;//记得还要新建一个,与后面的连续 
    }


    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值