Trie树
trie树又叫字典树,这个数据结构看名字就能知道跟字符串有关,且也跟字典有关,且这是一些高级的字符串算法的基础,其主要的结构便是如果给定一些字符串,我们把字符串的每一位拆开,每一位都建立一个节点,如果这个字符及其前缀已经存在于字典树中,那就可以继续向下建立它的后缀,知道这个字符串的节点全都遍历一遍。
比如说以下这个例子:
我们要建立“ ab”"ba"就可以建立以下这样的一个字典树。
如图:
因为该树像字典一样,所以叫字典树。知道了字典树是什么我们该怎么建立和使用呢。
插入:
因为字典树一开始肯定是空的,且我们肯定要插入几个节点,但是有可能我们不知道有几个字符串在这个字典树中。
比如下面这个例子:
插入“a” "ab" "abc" "abcd"
我们得到的字典树便是这样:
这样我们便不好分辨到底有几个字符串了,因此我们在建立时,如果每个节点都建完了,就在每个字符串的结尾加个标记。
我们便得到了以下的树:(黄色表示结尾)
接下来讲建立字典树的思想,因为像字典一样,所以我们在插入时先判断是否该节点在树中出现,如果没有就新建一个节点,并把当前节点与新加节点连起来,并把当前节点设为新加节点,直到要插入的字符串全部加入,别忘了在最后一定要加个标记。我们可以建立一个数组名叫:word[i],表示i这个编号的节点是否是最后一个节点。
void _insert(string s) { int now=0;//now指的是当前节点 int size=s.size();//size指要加入的字符串的大小 for(int i=0;i<size;i++) { int x=s[i]-'a'; if(!trie[now][x])如果该节点并没有在树中出现(即字母的位置),就新建一个节点,而trie数组是指的是字母的位置。 trie[now][x]=++total; now=trie[now][x]; } _word[now]=1; }
插入完之后不要忘了将word数组置为1。
如果我们要统计以i为结尾的前缀出现次数可以建立一个sum[i]数组,每遍历到i点就让sum[i]++。
这样就可以了。
查找:
我们学会了插入是仅仅不够的,我们还需要判断某个前缀是否在该字典树中出现过,这个其实也很简单,我们可以在遍历每个点时看这个点的子节点是否有这个点的下一个字符,如果没有就直接返回false,否则就继续寻找下去,直到该前缀被找完,可是我们如果要判断某个字符串的话,就不仅仅需要满足上述条件,还需要判断word[该节点的结尾]等不等于1。如果等于1,说明有这个字符串。
代码:
bool find(string s) { int now=0; int size=s.size(); for(int i=0;i<size;i++)//要把该字符串的每一个字符都遍历一遍 { int x=s[i]-'a'; if(!trie[now][x])//如果有一个不满足就失败 return 0; now=trie[now][x]; } return 1; }
这样Trie树的基本操作就讲完了,剩下的便就是利用了,其主要的用途便是实现AC自动机。
这个...以后再讲。