又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
假设有abc,abcd,abd, b, bcd,efg,hii这7个单词,可构建字典树如下:
查找一个字符串时,我们只需从根结点按字符串中字符出现顺序依次往下走。如果到最后字符串结束时,对应的结点标记为红色,则该字符串存在;否则不存在。
插入时也只需从根结点往下遍历,碰到已存在的字符结点就往下遍历,否则,建立新结点;最后标记最后一个字符的结点为红色即可。
性质
它有3个基本性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符。
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
每个节点的所有子节点包含的字符都不相同。
基本操作
其基本操作有:查找 插入和删除,当然删除操作比较少见.我在这里只是实现了对整个树的删除操作,至于单个word的删除操作也很简单.
搜索字典项目的方法为:
(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
其他操作类似处理
以上内容来自百度百科:。对应练习:ZOJ1109 HDU1251
ZOJ1109 Language of FatMouse
map方法 1320MS 9556K
#include<iostream> #include<string> #include<map> #pragma warning (disable:4786) using namespace std; int main() { map<string,string> m; int len,i; char str[40],a[20],b[20]; while(1) { gets(str); len=strlen(str); if(len==0) break; for(i=0;str[i]!=' ';i++); strncpy(a,str,i); a[i]=0; strncpy(b,str+i+1,len-i-1); b[len-i-1]=0; m[b]=a; } map<string,string>::iterator it; while(scanf("%s",str)!=EOF) { it=m.find(str); if(it!=m.end()) cout<<(*it).second<<endl; else puts("eh"); } return 0; }
字典树:140MS 14960K
#include<stdio.h> #include<stdlib.h> #include<string.h> #define N 100006 typedef struct node{ char s[12]; int h; struct node *next[26]; }*Tree,T; void init(Tree &root) { root=(Tree)malloc(sizeof(T)); root->h=0; for(int i=0;i<26;i++) root->next[i]=NULL; } void insert(char path[],char s[],Tree root) { int len,i,j; len=strlen(path); for(i=0;i<len;i++) { if(root->next[path[i]-'a']==NULL) { Tree t=(Tree)malloc(sizeof(T)); for(j=0;j<26;j++) { t->next[j]=NULL; t->h=0; } root->next[path[i]-'a']=t; } root=root->next[path[i]-'a']; } root->h=1; strcpy(root->s,s); } void find(char s[],Tree root) { int len,i; len=strlen(s); for(i=0;i<len;i++) { if(root->next[s[i]-'a']!=NULL) root=root->next[s[i]-'a']; else break; } if(i==len && root->h==1) puts(root->s); else puts("eh"); } int main() { Tree root; int len,i; char str[25],a[12],b[12]; init(root); while(1) { gets(str); len=strlen(str); if(len==0) break; for(i=0;str[i]!=' ';i++); strncpy(a,str,i); a[i]=0; strncpy(b,str+i+1,len-i-1); b[len-i-1]=0; insert(b,a,root); } while(scanf("%s",str)!=EOF) find(str,root); return 0; }
HDU1251 统计难题 140MS 43736K
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct node{ int cnt; struct node *next[26]; }*Tree,T; Tree root; void insert(char *str) //建字典树 { int i; Tree p,newnode; p=root; for(; *str;str++) { if(p->next[*str-'a']!=NULL) { p=p->next[*str-'a']; p->cnt++; } else { newnode=(Tree)malloc(sizeof(T)); for(i=0;i<26;i++) newnode->next[i]=NULL; p->next[*str-'a']=newnode; p=p->next[*str-'a']; p->cnt=1; } } } int find(char *str) //查找 { Tree p; p=root; for(;*str;str++) { if(p->next[*str-'a']!=NULL) p=p->next[*str-'a']; else return 0; } return p->cnt; } int main() { int i; char str[20]; root=(Tree)malloc(sizeof(T)); for(i=0;i<26;i++) root->next[i]=NULL; root->cnt=0; while(gets(str)) { if(strcmp(str,"")==0) break; insert(str); } while(gets(str)) printf("%d\n",find(str)); return 0; }
PKU1204 Word Puzzles
字典树:1485MS 14320K(对给定的单词建树,对表进行暴力search)
#include<stdio.h> #include<string.h> #include<stdlib.h> #define N 1002 typedef struct tree{ int count; struct tree *next[26]; }*Tree,T; Tree root; int l,c,w; char map[N][N]; int result[N][3]; int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}}; void insert(char *s,int con) { Tree p=root,q; for(int i=0;s[i];i++) { if(p->next[s[i]-'A']==NULL) { q=(Tree)malloc(sizeof(T)); memset(q->next,0,sizeof(q->next)); q->count=-1; p->next[s[i]-'A']=q; } p=p->next[s[i]-'A']; } p->count=con; } void search(int x,int y,int k) { int x1=x,y1=y; Tree p=root; while(x1>=0 && x1<l && y1>=0 && y1<c) { int id=map[x1][y1]-'A'; if(p->next[id]==NULL) break; else p=p->next[id]; if(p->count!=-1) { result[p->count][0]=x; result[p->count][1]=y; result[p->count][2]=k+'A'; } x1+=dir[k][0]; y1+=dir[k][1]; } } void slove() { int i,j,k; for(i=0;i<l;i++) for(j=0;j<c;j++) for(k=0;k<8;k++) search(i,j,k); for(i=0;i<w;i++) printf("%d %d %c\n",result[i][0],result[i][1],result[i][2]); } int main() { int i; char word[N]; scanf("%d%d%d",&l,&c,&w); getchar(); root=(Tree)malloc(sizeof(T)); memset(root->next,0,sizeof(root->next)); for(i=0;i<l;i++) gets(map[i]); for(i=0;i<w;i++) { gets(word); insert(word,i); } slove(); return 0; }
据说这题还可以用AC自动机实现,不了解AC自动机,有待提高……
HDU1075 同ZOJ1109同一道理,字典树基本应用。
map方法 3375MS 42368K 752B
#include<iostream> #include<string> #include<map> using namespace std; int main() { map<string,string> M; string a,b; cin>>a; while(cin>>a,a!="END") { cin>>b; M[b]=a; } cin>>a; getchar(); char tmp[3005]; while(gets(tmp),strcmp(tmp,"END")) { int len=strlen(tmp); tmp[len++]=' '; tmp[len]=0; b=""; for(int i=0;i<len;i++) { if(!islower(tmp[i])) { if(M[b]!="") cout<<M[b]; else cout<<b; b=""; if(i!=len-1) cout<<tmp[i]; } else b+=tmp[i]; } cout<<endl; } return 0; }
字典树:437MS 59796K 1274B(可以用做模板了吧)
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> typedef struct node{ node *next[26]; int h; char word[12]; node() { h=0; memset(next,0,sizeof(next)); } }*Tree,T; Tree root=new node(); void insert(char *eng,char *mar) { Tree p=root; while(*mar) { int id=*mar-'a'; if(p->next[id]==NULL) p->next[id]=new node(); p=p->next[id]; mar++; } p->h=1; strcpy(p->word,eng); } char *find(char *str) { Tree p=root; while(*str) { int id=*str-'a'; if(p->next[id]==NULL) break; p=p->next[id]; str++; } if(*str==NULL && p->h==1) return p->word; else return NULL; } int main() { int i,k,len; char a[12],b[12],tmp[3005],tp[3005]; char *p; scanf("%s",a); while(scanf("%s",a) && strcmp(a,"END")!=0) { scanf("%s",b); insert(a,b); } scanf("%s",a); getchar(); k=0; while(gets(tmp),strcmp(tmp,"END")) { len=strlen(tmp); tmp[len++]=' '; tmp[len]=0; for(i=0;i<len;i++) { if(!islower(tmp[i])) { tp[k]=0; k=0; p=find(tp); if(p) printf("%s",p); else printf("%s",tp); if(i!=len-1) putchar(tmp[i]); } else tp[k++]=tmp[i]; } puts(""); } return 0; }