Trie树的键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀(prefix),从根节点到当前结点的路径上的所有字母组成当前位置的字符串,结点可以保存当前字符串、出现次数、指针数组(指向子树)以及是否是结尾标志等等。
typedef struct Trie_Node { char count[15]; //单词前缀出现的次数 struct Trie_Node* next[MAXN]; //指向各个子树的指针 bool exist; //标记结点处是否构成单词 }Trie;
Trie树可以利用字符串的公共前缀来节约存储空间,如下图所示:
它有3个基本性质:
(1) 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
(2) 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
(3) 每个节点的所有子节点包含的字符都不相同。
(三)Trie树的基本操作
(1)插入操作
按下标索引逐个插入字母,若当前字母存在则继续下一个,否则new出当前字母的结点,所以插入的时间复杂度只和字符串的长度n有关,为O(n)。
void Insert(Trie *root, char* s,char *add) { Trie *p=root; while(*s!='\0') { if(p->next[*s-'a']==NULL) { p->next[*s-'a']=createNode(); } p=p->next[*s-'a']; // p->count=add; ++s; } p->exist=true; strcpy(p->count,add); }(2)查询操作
int Search(Trie* root,const char* s) { Trie *p=root; while(*s!='\0') { p=p->next[*s-'a']; if(p==NULL) return 0; ++s; } return p->count; }
(3)删除操作
一般来说,对Trie单个结点的删除操作不常见,所以我在这里也只提供递归删除整个树的操作
void del(Trie *root) { for(int i=0;i<MAXN;i++) { if(root->next[i]!=NULL) { del(root->next[i]); } } // free(root); delete root; }
(4)遍历操作
如果我们想要将trie中的字符串排序输出,直接先序遍历即可。
void Print(Trie *root) { Trie *p=root; if(p->exist) cout<<p->name<<": "<<p->count<<endl; for(int i=0;i<26;i++) { if(p->next[i]!=NULL){ Print(p->next[i]); } } }(四)Trie树的具体应用
//hdu 1251 统计前缀出现次数 #include <cstdio> #include <iostream> #include <string> #include <cstring> using namespace std; const int MAXN=26; typedef struct Trie_Node { int count; //单词前缀出现的次数 struct Trie_Node* next[MAXN]; //指向各个子树的指针 bool exist; //标记结点处是否构成单词 }Trie; Trie* createNode() { //Trie* p =(Trie*)malloc(sizeof(Trie)); Trie *p=new Trie; p->count=0; p->exist=false; memset(p->next,0,sizeof(p->next)); return p; } void Insert(Trie *root, const char* s) { Trie *p=root; while(*s!='\0') { if(p->next[*s-'a']==NULL) { p->next[*s-'a']=createNode(); } p=p->next[*s-'a']; p->count+=1; ++s; } p->exist=true; } int Search(Trie* root,const char* s) { Trie *p=root; while(*s!='\0') { p=p->next[*s-'a']; if(p==NULL) return 0; ++s; } return p->count; } void del(Trie *root) { for(int i=0;i<MAXN;i++) { if(root->next[i]!=NULL) { del(root->next[i]); } } // free(root); delete root; } int main() { char s[15]; bool flag=false; Trie* root=createNode(); while(gets(s)) { if(flag) { int ans=Search(root,s); printf("%d\n",ans); } else { if(strlen(s)!=0) Insert(root,s); } if(strlen(s)==0) flag=true; } del(root); return 0; }(2)翻译(密码,明文)
/* //hdu 1075映射 #include <cstdio> #include <iostream> #include <string> #include <cstring> #include <stdlib.h> using namespace std; const int MAXN=26; typedef struct Trie_Node { char count[15]; //单词前缀出现的次数 struct Trie_Node* next[MAXN]; //指向各个子树的指针 bool exist; //标记结点处是否构成单词 }Trie; Trie* createNode() { Trie* p =(Trie*)malloc(sizeof(Trie)); p->exist=false; memset(p->next,0,sizeof(p->next)); return p; } void Insert(Trie *root, char* s,char *add) { Trie *p=root; while(*s!='\0') { if(p->next[*s-'a']==NULL) { p->next[*s-'a']=createNode(); } p=p->next[*s-'a']; // p->count=add; ++s; } p->exist=true; strcpy(p->count,add); } void Search(Trie* root, const char* s) { Trie *p=root; while(*s!='\0') { if(p->next[*s-'a']==NULL) { printf("%s",s); return ; } p=p->next[*s-'a']; ++s; } if(p->exist) printf("%s",p->count); else printf("%s",s); } void del(Trie *root) { for(int i=0;i<MAXN;i++) { if(root->next[i]!=NULL) { del(root->next[i]); } } free(root); } int main() { char text[3013],from[15],to[15]; Trie* root=createNode(); scanf("%s",from); while(scanf("%s",from),strcmp(from,"END")) { scanf("%s",to); Insert(root,to,from); } scanf("%s",from); getchar(); while(gets(text),strcmp(text,"END")) { int len=strlen(text); for(int i=0;i<len;i++) { if(islower(text[i])) { int j=0; char temp[15]; memset(temp,'\0',sizeof(temp)); while(islower(text[i])) temp[j++]=text[i++]; Search(root,temp); } if(!islower(text[i])) printf("%c",text[i]); } printf("\n"); } return 0; } */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<string> using namespace std; struct node{ char dic[15]; node * next[26]; bool flag; }*root; node *build() { node *p=(node *)malloc(sizeof(node)); for(int i=0;i<26;i++) p->next[i]=NULL; p->flag=false; return p; } void insert(char *earth,char *mars) { int len=strlen(mars); node *p; p=root; for(int i=0;i<len;i++) { if(p->next[mars[i]-'a']==NULL) p->next[mars[i]-'a']=build(); p=p->next[mars[i]-'a']; } p->flag=true; strcpy(p->dic,earth); } void query(char *earth) { int len=strlen(earth); node *p; p=root; for(int i=0;i<len;i++) { if(p->next[earth[i]-'a']==NULL) { printf("%s",earth); return; } p=p->next[earth[i]-'a']; } if(p->flag) printf("%s",p->dic); else printf("%s", earth); } int main() { char earth[15],mars[15],ask[3010]; scanf("%s",earth); root=build(); while(scanf("%s",earth),strcmp(earth,"END")) { scanf("%s",mars); insert(earth,mars); } scanf("%s",earth); getchar(); while(gets(ask),strcmp(ask,"END")) { int len=strlen(ask); for(int i=0;i<len;i++) { if(islower(ask[i])) { int j=0; memset(earth,'\0',sizeof(earth)); while(islower(ask[i])) earth[j++]=ask[i++]; query(earth); } if(!islower(ask[i])) printf("%c",ask[i]); } printf("\n"); } return 0; }(3)实现搜索引擎的热门搜索排名
/ 自动补全 #include <cstdio> #include <iostream> #include <string> #include <cstring> using namespace std; const int MAXN=26; typedef struct Trie_Node { int count; //单词出现的次数 struct Trie_Node* next[MAXN]; //指向各个子树的指针 bool exist; //标记结点处是否构成单词 char name[15]; }Trie; Trie* createNode() { Trie* p =(Trie*)malloc(sizeof(Trie)); p->count=0; p->exist=false; memset(p->next,0,sizeof(p->next)); return p; } void Insert(Trie *root,char* word) { Trie *p=root; char *s=word; while(*s!='\0') { if(p->next[*s-'a']==NULL) { p->next[*s-'a']=createNode(); } p=p->next[*s-'a']; ++s; } p->exist=true; p->count+=1; strcpy(p->name,word); } Trie* Search(Trie* root, char* s) { Trie *p=root; while(*s!='\0') { p=p->next[*s-'a']; if(p==NULL) return 0; ++s; } return p; } void del(Trie *root) { for(int i=0;i<MAXN;i++) { if(root->next[i]!=NULL) { del(root->next[i]); } } free(root); } void Print(Trie *root) { Trie *p=root; if(p->exist) cout<<p->name<<": "<<p->count<<endl; for(int i=0;i<26;i++) { if(p->next[i]!=NULL){ Print(p->next[i]); } } } int main() { char s[15]; Trie* root=createNode(); for(int i=0;i<5;i++) { cin>>s; Insert(root,s); } while(cin>>s) { Trie *ans=Search(root,s); if(ans) Print(ans); } del(root); return 0; }