练习:Trie树(公共前缀)

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

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

《练习: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;
}

    原文作者:Trie树
    原文地址: https://blog.csdn.net/cleopard66/article/details/50593892
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞