Trie树,也叫字典树,可以很方便的储存很多个字符串。以小写英文单词为例,Trie树就是一颗26叉树,每一个节点保存一个英文字母。根节点什么也不保存,从根节点开始,第一层就代表单词的第一个字母,向下直到没有字母为止,就是一个单词。
poj2001 题意是给你最多1000个字符串,要你对于每一个字符串,输出它的最短的一个前缀,通过这个前缀能切仅能在1000个字符串中检索到它自己。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 50000;
const int size = 26;
int ac[maxn][size]; //存放所有节点的大数组,把所有节点存在一个数组里,有点像链式向前星。存放的值是先一个节点在这个大数组中的位置。
int num[maxn]; //有多少个单词用到了当前节点。
int top; //类比链式向前星里面的top,表示当前用过了多少节点。
int idx(char c) {return c-'a';}
void clear(){
memset(ac[0],0,sizeof(ac[0]));
top=1;
} //清空,只要把根节点清零就好了。
int New(){
memset(ac[top],0,sizeof(ac[top]));
num[top]=0;
return top++;
} //如果要用到一个新的节点用这个函数,返回值是新节点在ac数组中的位置。
void insert(char *s){
int k=0,L=strlen(s);
for(int i=0;i<L;++i){
int c=idx(s[i]);
if(!ac[k][c]){
ac[k][c]=New();
} //如果当前位置没有走到过,就在ac数组中腾一个位置给它。
k=ac[k][c]; //走向下一个节点。
num[k]++; //又有一个单词经过了当前节点。
}
} //插入一个新的单词。
void find(char *s){
int k=0,L=strlen(s);
for(int i=0;i<L;++i){
printf("%c",s[i]);
int c=idx(s[i]);
k=ac[k][c];
if(num[k]==1){
printf("\n");
return ;
}
}
printf("\n");
} //根据题意可以调整find函数,总体用法和insert函数差不多。。
char s[1005][100];
int main()
{
// freopen("data.in","r",stdin);
clear();
int k=0;
while(scanf("%s",s[k])!=EOF){
insert(s[k++]);
}
for(int i=0;i<k;++i){
printf("%s ",s[i]);
find(s[i]);
}
return 0;
}