练习:Trie树(公共前缀)

来源:互联网 发布:mac手绘用什么软件 编辑:程序博客网 时间:2024/06/04 20:03

Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构。

它的精髓在于利用字符串的公共前缀来节约存储空间。从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。(举例如下图)


Trie树的应用很多,主要是以下几个方面:

(1)正如“前缀树”的定义一样,Trie树可以方便地检索字符串,查找字符串的公共前缀等。更为重要的是,建立Trie树的过程,其实也是查询的过程。

(2)排序。只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。

(3)其他数据结构和算法的基础:如AC自动机、后缀树等。


下面通过hihoCoder上的一个例子,编程练习。

给定一个含有n(n≤100000)个单词的字典,每个单词由不超过10个的小写英文字母组成(可能存在相同的单词,此时应将其视作不同的单词)。

接下来有m(m≤100000)次询问,每次询问要求回答字典中以给定字符串为前缀的单词的个数

【样例输入】

5
babaab
babbbaaaa
abba
aaaaabaa
babaababb
5
babb
baabaaa
bab
bb
bbabbaab

【样例输出】

1
0
3
0
0

【我的程序】

这是Trie树的经典练习,在程序中,我采用孩子兄弟表示法来储存这棵Trie树。

#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct triNode //孩子兄弟表示法{    char c;    long int num;    struct triNode* fChild;    struct triNode* rCousin;}* triTree;triTree newTree(char c) //新建一棵子树{    triTree p=(triTree) malloc(sizeof(struct triNode));    p->c=c;    p->num=1;    p->fChild=NULL;    p->rCousin=NULL;    return p;}void dictionary(triTree t) //建立字典树{    long int n,i;    char s[11];    scanf("%ld",&n);    for (i=0;i<n;i++)    {        scanf("%s",s);        long int len=strlen(s),j,k;        triTree x=t,y;        for (j=0;j<len;j++)        {            y=x->fChild;            if (y==NULL) //当前结点没有子树,则将剩余字符串全部插入            {                for (k=j;k<len;k++)                {                    x->fChild=newTree(s[k]);                    x=x->fChild;                }                break;            }            int flag=0;            while (y!=NULL)            {                if (y->c==s[j]) {flag=1;break;}                x=y;                y=y->rCousin;            }            if (flag==0) //未找到当前字符,则增加一棵子树作为右兄弟            {                x->rCousin=newTree(s[j]);                x=x->rCousin;                for (k=j+1;k<len;k++)                {                    x->fChild=newTree(s[k]);                    x=x->fChild;                }                break;            }            else //找到当前字符,将经过当前结点的字符串个数加1            {                x=y;                x->num++;            }        }    }}void response(triTree t) //查询过程和建树过程同理,且更简单{    long int m,i;    scanf("%ld",&m);    for (i=0;i<m;i++)    {        char s[30];        scanf("%s",s);        long int len=strlen(s),j;        triTree y=t;        for (j=0;j<len;j++)        {            y=y->fChild;            if (y==NULL) {printf("0\n");break;}            while (y!=NULL)            {                if (y->c==s[j]) break;                y=y->rCousin;            }            if (y==NULL) {printf("0\n");break;}        }        if (j==len) printf("%ld\n",y->num);    }}int main(){    triTree t=newTree('0');    dictionary(t);    response(t);    return 0;}

1 0
原创粉丝点击