以树形结构存储大量字符串——字典树

· · 个人记录

学习目标:熟练写出trie树

一、什么是字典树

字典树即trie树,是一种在工程中没有任何卵用的数据结构,在信息竞赛中应用广泛的数据结构。同时,它也是AC自动机的基础。

二、字典树的结构

如果字符串的字符集是小写英文字母,那么字典树是26叉树。字符集有多大,每个节点就有多少个子节点。

因此,以小写英文字母为字符集,字典树的节点形式如下:

struct Node
{
    int ch[26],cnt,isEnd;
}

其中,ch[26]代表26个子节点的模拟指针,cnt表示经过这里的字符串个数,isEnd表示它是几个字符串的结尾节点。这些可以根据需要增减。

不难发现,根节点到一个isEnd!=0的节点的路径代表一个字符串,根节点到一个cnt!=0的节点的路径代表一个前缀。

像这样。

三、字典树的插入

首先要有一个根节点。

int root=0;

还要给子节点分配内存。

int cnt=0;

每当要加入节点时,分配下标++cnt。

然后,依据字符串从前到后的每个字符在字典树上走路,直到走完,一路上维护信息:

using std::string;
void insert(string s)
{
    int now=root;
    for(int i=0;i<s.length();++i)
    {
        ++node[now].cnt;
        if(!node[now].ch[s[i]-'a'])
        {
            node[now].ch[s[i]-'a']=++cnt;
        }
        now=node[now].ch[s[i]-'a'];
    }
    ++node[now].cnt;
    ++node[now].isEnd;
}

四、字典树的查询

1、查询字符串

P2580 于是他错误的点名开始了

像这道题。

trie树的查询和插入非常相似,只要在树上走路即可:

bool count(string s)
{
    int now=root;
    for(int i=0;i<s.length();++i)
    {
        if(!node[now].ch[s[i]-'a'])
            return false;
    }
    return node[now].isEnd;
}

2、查询前缀

把最后一行改成

return true;

即可。

五、例题

P2922 USACO08DEC 秘密消息Secret Message

P4683 IOI2008 Type Printer 打印机