字典树Trie

字典树,顾名思义,就是把字典放到树上ui

不不不,是用字典来建树spa

把树建成字典的样子?指针

差很少。code

字典树指的是某个字符串集合对应的有根树,树的每条边上刚好对应一个字符,每一个顶点表明从根到该节点的路径所对应的字符串(将全部通过的边上的字符按照顺序链接起来)。有时咱们也称trie上的边为转移,节点为状态blog

是否是读起来很恶心字符串

其实能够这么理解string

字典树就是一棵利用了字符串的公共前缀(好比gcakioi和gcakimo的前缀就是gcaki)来减小查询时间的树。当你查询单词的时候,只要沿着转移边查找就能够了,而且对于每一个单词的结尾,在字典树上都会有标记来表示这是一整个单词。io

举个例子class

如今有两个单词gc

A:GCAKIOI

B:GCAKIMO

那么这个字典树大概就是这个样子

 

很是直观对吧

就是在相同的时候合到一块儿,不一样的时候分开,在单词结尾进行标记就行了

操做实现:

1.初始化

  一棵空的trie只包含一个根节点,该点的字符指针都指向空

int ch[N][Z]//Z为字符集大小,ch[i][j]表示节点i的j字符指向的节点
bool bo[N]//对给以i为终止字符的节点打标记

 

2.插入

  当须要插入一个字符串S的时候,咱们令一个指针P指向根节点,而后依次扫描S中的每一个字符c

  •   若是指针P的c字符指针指向一个存在的节点Q,则令P=Q
  •        若是指针P的c字符指针指向空,则新建一个节点Q,令P的c字符指针指向Q,而后令P=Q
  •        当S中的字符扫描完毕时,在当前节点指针P上标记它是一个字符串的末尾

 

inline void build(string s,int id)
{
    int now=1,len=s.size();
    rep(i,0,len-1)
    {
        int c=s[i]-'a';
        if(!ch[now][c])
        {
            ch[now][c]=++cnt;
        }//若是尚未这个节点,就新建立一个节点 
        now=ch[now][c];//当前节点转移过去 
    }
    bo[now]=id;//给以节点now为终止节点的打上标记 
}

 

 

 

3.查询

  当咱们要查询一个字符串S在trie中是否出现时,咱们令一个指针P起初指向根节点,而后依次扫描S中的每个字符c

  •   若是指针P的c字符指针指向空,则说明S没有被插入过trie
  •        若是指针P的c字符指针指向一个已经存在的节点Q,则令P=Q
  •        当S中的字符扫描完毕时,若当前节点P被标记为一个字符串的末尾,则说明S在trie中已经存在,不然说明S没有被插入过trie

 

inline bool find(char s[])
{
    int now=1,len=strlen(s),c,k;
    rep(i,0,len-1)//在字典树上查找该单词 
    {
        c=s[i]-'a';
        if(!ch[now][c]) return false;
        now=ch[now][c];
    }
    return true;
}

 

当字符均为小写字母或者大写字母时,trie能够当作一个26叉树

它的空间复杂度为O(N*C),N是节点个数,C是字符集的大小