您的位置:首页 > 其它

Trie

2016-05-21 13:50 302 查看

Trie 字典树的实现

Trie 又叫字典树、前缀树,属于一种高级排序树。它主要用来保存字符串集。



上图所示即为一颗Trie,标识的字符串集合为{a,to,tea,ted,ten,i,in,inn},每个单词的结束位置对应一个“单词结点”。反过来,从根节点到每个单词结点的路径上所有的字符连接起来就是这个结点对应的字符串。我们可以将根结点标为0(注意,根结点不保存任何字符),其余结点从1开始标号(正整数),这样就可以用数组来存了。(当然,也可以不这么做,使用链表存储)

在这里,我们可以用ch[i][j]表示节点i对应的ASCII码为j的那个字符的子结点,如果这个子结点不存在,让ch[i][j]=0(这样并不会引起歧义,因为任何结点的子结点不可能是根结点)。然而,利用Trie时,我们往往需要给结点加上一些附加信息,比如:从根到该结点处的字符串是否可以表示一个单词、该单词的中文翻译等等,我们把这个附加信息保存在val[i]中即可。

那么,代码就很显然了

插入:

hljs cpp">void insert(char *s,int v){
int u=0,n=strlen(s);
for (int i=0;i<n;i++){
int c=idx(s[i]);
if (!ch[u][c]){ //结点不存在
ch[u][c]=create();
}
u=ch[u][c]; //往下走
}
val[u]=v
}


以下是利用Trie实现词典的查询和插入操作:

hljs cpp">#include<iostream>
#include<cstring>
using namespace std;

const int maxn=1001,sigma_size=127;

struct trie{
trie(){ //初始化
memset(ch,0,sizeof(0));
memset(val,0,sizeof(val));
sz=1;
}
private:
int ch[maxn][sigma_size],sz; //sz 为结点总数
char val[maxn][maxn];
int idx(char t){return (int)t;}
int create(){ //新建结点
memset(ch[sz],0,sizeof(ch[sz]));
memset(val[sz],0,sizeof(val[sz]));
return sz++;
}
public:
void insert(char *s,char* v){ //插入
int u=0,n=strlen(s);
for (int i=0;i<n;i++){
int c=idx(s[i]);
if (!ch[u][c]){ //结点不存在
ch[u][c]=create();
}
u=ch[u][c]; //沿着路径往下走
}
memcpy(val[u],v,sizeof(v)); //将v中的值保存在val[u]中,如果是int类型,将val定义为int[],这里就只需要val[u]=v
}
char* query(char *s){ //查询
bool flag=true;
int u=0,n=strlen(s);
for (int i=0;i<n;i++){
int c=idx(s[i]);
if (!ch[u][c]) { //结点不存在,即没查到
flag=false;
break;
}
u=ch[u][c]; //往下走
}
return (flag&&val[u]!=NULL)?val[u]:NULL; //如果val[u]=NULL代表从根到该结点不是个单词
}
};

int main(){
trie x;
char *p=new char[100];
char *t=new char[100];
int k,m;
cin>>k>>m;
while (k--){
scanf("%s%s",p,t);
x.insert(p,t); //插入
}
while (m--) {
scanf("%s",p); //查询
printf("%s\n",x.query(p));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  trie 字典树 前缀树