引入
假如我们给出大量的字符串,查询其中某两串的公共前缀,显然不断枚举比较是否相同的办法对于多次询问太慢了,这就要用到Trie树。
Trie树即字典树,是一种能快速检索字符串的多叉树,但是Trie树的内存消耗很大,是用空间换时间的思想。那么它是如何实现的呢?
原理
假如给出abc,abd,abcd,bcd,efg五个字符串,先来看看构造出来的树。
我们发现根节点是没有字符;第一字符不同在不同的子树上,而abc,abd第一字符相同就在同一子树上;而abc和abd由于最后一个字符不同,所以又分支了出去。原理十分简单。
如果我们已经将一个字符串输完了,只需要将最后节点标记一下,下次遍历时只要到了该节点,那么搜到的所有点组合起来就是该字符串。
我们来详细地了解如何建立和查询一棵Trie树。
建立
我们开一个二维数组存储,trie[ i ][ j ],表示i节点的第j个子节点的编号为a,其中如果是小写字母那么第二维就可以是26,0~9的数字那么就是10。
我们再引入一个指针p来指向i这个节点,如果trie[p][i]==0,说明该字符还没建立,那就建立并把p移到该新节点上,如果trie[p][i]!=0那么就说明这里已经建了,就直接跳到它的子节点。
void Build()
{
int p=0;
for(int i=0;i<strlen(str);i++)
{
if(trie[p][str[i]-'a']==0)
{
trie[p][str[i]-'a']=++tot;
}
p=trie[p][str[i]-'a'];
}
}
查询
例如查询一个字符串,看它是否在字典树中。
首先第一个节点,如果得到的编号没有定义如等于0,那么说明不存在,如果第一个节点编号存在,那么就跳到它下面的一个编号,继续判定。如果全部枚举完了,并且最后一个节点有标记了是一个字符串,那么就找到了。
int Search()
{
int p=0;
for(int i=0;i<strlen(str);i++)
{
if(trie[p][str[i]-'a']==0) return 0;
p=trie[p][str[i]-'a'];
}
return 1;
}
板子传送门HDU 1251
#include<bits/stdc++.h>
using namespace std;
#define N 100005
int trie[N][26];
int ed[N];
int tot;
char str[15];
void Build()
{
int p=0;
for(int i=0;i<strlen(str);i