现在的位置: 首页 > 综合 > 正文

字典树小结

2017年10月13日 ⁄ 综合 ⁄ 共 4089字 ⁄ 字号 评论关闭

没有见到过字典树的时候,以为会很神秘。

其实,如果链表学的差不多了,实现字典树那就是手到擒来。

做了几道题,效果还好。。

第一道:

NYOJ 290 动物统计加强版 点击打开链接

典型的字典树。裸的字典树。还是比较好的。不是太坑。算是练手了吧。直接就写了,也不用放内存什么的。但是,最好的还是把内存给放了吧,要不太占内存。

直接代码:

 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N=26;
struct Node{
    int count;
    Node *next[N];
}*root;
int MaxConut=-1;
char ans[N];

Node* Build(){//建立以个节点,每个节点都最多有26个子节点,虽然真真的子节点数不确定.
    Node* p=(Node*)malloc(sizeof(Node));
    for(int i=0;i<N;i++){
        p->next[i]=NULL;
    }
    p->count=0;
    return p;
}

void Save(char *s){//保存word
    int len=strlen(s);
    if(len==0) return ;
    Node* p=root;
    for(int i=0;i<len;i++){
        if(p->next[s[i]-'a']==NULL)
        p->next[s[i]-'a']=Build();//不存在的话建立该节点.
        p=p->next[s[i]-'a'];
    }
    p->count++;
    if(p->count>=MaxConut) {
        MaxConut=p->count;
        strcpy(ans,s);
    }
}

int main(){
//    freopen("Input.txt","r",stdin);
    int n;
    scanf("%d",&n);
    root=Build();
    char animal[N];
    for(int i=1;i<=n;i++){
        scanf("%s",animal);
        Save(animal);
    }
    printf("%s %d\n",ans,MaxConut);
    return 0;
}
        

可以看到,其实,字典树,写起来也就50行的事情。不难。

第二道:

Phone List Hdu 1671
点击打开链接
 Poj 3630
点击打开链接
 NYOJ 163
点击打开链接

这题就比较坑点了。同样的代码,在Hdu,ML。在Poj TL。在NYOJ上WA。

只能说,数据不同,结果也会有所不同。由此可见,数据的重要性。

这题,也是比较裸的字典树吧。

有两中情况,一,先存了比较短的(也就是前缀)。二,先存了比较长的。这两中各判断一下就可以。

说明一下为什么会出现不同的结果。

Hdu,ML。就是因为自己没有释放内存,导致,无用内存积累,开辟新的内存又过多,导致ML。

Poj,TL。就是因为在动态分配内存的时候,过多的调用各种函数,导致超时。这时候就需要静态的来开辟空间了。

NYOJ,WA。这个是因为,自己在判断两种的时候,有一点小小的错误。

动态:

 
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;


const int N=10;
struct Node{
    bool  m;
    Node *next[N];
};

Node* Build(){
    Node *p=(Node*)malloc(sizeof(Node));
    for(int i=0;i<N;i++){
        p->next[i]=NULL;
    }
    p->m=false;
    return p;
}

bool Save(char *s,Node *root){
    int i,len=strlen(s);
//    if(len==0) return false;
    Node *p=root;
    bool snack=false;
    for(i=0;i<len;i++){
        if(p->next[s[i]-'0']==NULL){
            p->next[s[i]-'0']=Build();
            snack=true;//没有开辟过新的空间.
        }
        else {
            if(p->next[s[i]-'0']->m)
            return true;
        }
        p=p->next[s[i]-'0'];
    }
    if(!snack) return true;
    p->m=true;
    return false;
}

void del(Node* p){
    for(int i=0;i<N;i++){
        if(p->next[i]!=NULL)
        del(p->next[i]);
        delete(p->next[i]);
    }
}

int main(){
//    freopen("1.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        char number[N];
        scanf("%d",&n);
        Node *root=Build();
        bool flag=false;
        for(int i=1;i<=n;i++){
            scanf("%s",number);
            if(!flag)
            flag=Save(number,root);
        }
        if(flag) printf("NO\n");
        else printf("YES\n");
        del(root);
    }
    return 0;
}        

静态:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N=10;
const int M=1000003;
struct Node{
    bool flag;
    Node *next[N];
}node[M];
int top;

Node* Build(){
    Node *p=&node[top++];
    for(int i=0;i<N;i++){
        p->next[i]=NULL;
    }
    p->flag=false;
    return p;
}

bool Save(char *s,Node* root){
    int len=strlen(s);
    if(len==0) return false;
    Node *p=root;
    bool mark=false;
    for(int i=0;i<len;i++){
        if(p->next[s[i]-'0']==NULL){
            mark=true;
            p->next[s[i]-'0']=Build();
        }
        else if(p->next[s[i]-'0']->flag){
            return true;
        }
        p=p->next[s[i]-'0'];
    }
    if(!mark) return true;
    p->flag=true;
    return false;
}

int main(){
//    freopen("1.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        char number[N];
        bool ans=false;top=0;
        Node *root=Build();
        for(int i=1;i<=n;i++){
            scanf("%s",number);
            if(!ans) ans=Save(number,root);
        }
        if(ans) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

很给力的题目。

第三道:
NYOJ  685 查找字符串
点击打开链接

还是裸的字典树。

直接代码:

 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N=17;
const int M=29;
struct Node{
    int count;
    Node* next[M];
}*root;

Node* Build(){
    Node* p=(Node*)malloc(sizeof(Node));
    for(int i=0;i<M;i++){
        p->next[i]=NULL;
    }
    p->count=0;
    return p;
}

int find(char x){
    if(x>='a'&&x<='z') return x-'a';
    else if(x=='@') return 27;
    else if(x=='+') return 28;
    else return -1;
}

void Save(char *s){
    int len=strlen(s);
    if(len==0) return ;
    Node *p=root;
    for(int i=0;i<len;i++){
        int k=find(s[i]);
        if(p->next[k]==NULL){
            p->next[k]=Build();
        }
        p=p->next[k];
    }
    p->count++;
}

int search(char *s){
    int len=strlen(s);
    Node* p=root;
    for(int i=0;i<len;i++){
        int k=find(s[i]);
        if(p->next[k]==NULL)
        return 0;
        p=p->next[k];
    }
    return p->count;
}

void del(Node *p){
    for(int i=0;i<M;i++){
        if(p->next[i]!=NULL)
        del(p->next[i]);
        delete(p->next[i]);
    }
}

int main(){
//    freopen("Input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        char word[N];
        root=Build();
        for(int i=1;i<=n;i++){
            scanf("%s",word);
            Save(word);
        }
        for(int i=1;i<=m;i++){
            scanf("%s",word);
            if(strlen(word)>15) printf("0\n");
            else printf("%d\n",search(word));
        }
        del(root);
    }
    return 0;
}        

比较简单。

今天的字典树就先告一段落了。

抱歉!评论已关闭.