Trie树就是字符树,其核心思想就是空间换时间。
举个简单的例子。
给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。
现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……
假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。
对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
这样一来我们询问和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。
我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。
看个例子把,也是转载的,继续学习!
http://acm.szu.edu.cn/wiki/index.php/Problem:H67:ACgirl%27s_SMS_guards
//trie树部分:给一组手机号,查找某一手机号是否在这一组手机号。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
//#include<string.h>
using namespace std;
node data[1100100];
int pointer = 0;
node * root;
typedef struct node
{
struct node * pNext[10];
bool isEnd;
node()
{
isEnd = false;
}
}node;
node * getNode()
{
return &data[pointer++];
}
void insert(node * root, char * strTel)
{
node * pCur = root;
int pos = 0;
while (*strTel)
{
pos = *strTel - '0';
if (NULL == pCur->pNext[pos])
{
pCur->pNext[pos] = getNode();
}
pCur = pCur->pNext[pos];
++strTel;
}
pCur->isEnd = true;
}
//查询手机号是否为黑名单
bool query(node * root, char * strTel)
{
node * pCur = root;
int pos = 0;
while (*strTel)
{
if (!(*strTel >= '0' && *strTel <= '9'))
{
return false;
}
pos = *strTel - '0';
if (NULL == pCur->pNext[pos])
{
return false;
}
pCur = pCur->pNext[pos];
++strTel;
}
if (!pCur->isEnd)
{
return false;
}
return true;
}
int main()
{
long year,month,day,hour,minute,second,k,m,i,j,ans,n,Case=1,flag,num;
char p[14],q[130],tel[130],con[130];
scanf("%ld",&n);
while(n--)
{
ans=0;
root = getNode();
printf("Case %ld:\n",Case++);
scanf("%ld",&m);
getchar();
for(i=0;i<m;i++)
{
gets(p);
insert(root,p);
}
scanf("%ld",&k);
getchar();
for(i=0;i<k;i++)
{
gets(q);
num=sscanf(q,"%ld-%ld-%ld:%ld:%ld:%ld,%[0-9],%[^'/0']",&year,&month,&day,&hour,&minute,&second,tel,con);
if(num!=8)
continue;
if(month>12||month<1)
continue;
if(day<1)
continue;
if((year%4==0&&year%100!=4)||year%400==0)
{
if(month==2&&day>29)
continue;
}
else
{
if(month==2&&day>28)
continue;
}
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
{
if(day>31)
continue;
}
else
{
if(day>30)
continue;
}
if(hour>23||hour<0||minute>59||minute<0||second>59||second<0)
continue;
if(strlen(tel)>11)
{
continue;
}
if(strlen(con)>100)
continue;
if(!query( root,tel))
continue;
j=0;
while(q[j]!=',')
{
printf("%c",q[j]);
j++;
}
printf(",15980698888,Sorry,I am ACb0y's girl friend\n");
ans++;
}
printf("count = %ld\n",ans);
}
system("pause");
}