1. trie树,又名字典树,顾名思义,它是可以用来作字符串查找的数据结构,它的查找效率比散列表还要高。
trie树的建树:
比如有字符串”ab” ,“adb”,“adc” 可以建立字典树如图:
树的根节点head不存储信息,它有26个next指针,分别对应着字符a,b,c等。插入字符串ab时,next[‘a’-‘a’]即next[0]为空,这是申请一个结点放在next[0]的位置,插入字符串db时,next[‘d’-‘a’]即next[3]为空,这时申请一个结点tmp放在next[3]的位置,接下来,tmp的后向结点tmp->next[‘a’-‘a’]即tmp->next[0]为空,在申请一个结点放在tmp->next[0]的位置。 插入字符串dc时,检查head->next[3]不为空,然后检查tmp->next[2]为空,这时申请一个结点放在tmp->next[2]的位置。
字典树的建树过程就是字符串不断插入的过程。
字典树的查找可以按照如下步骤进行:比如查找字符串”dc”,先检查head->next[3]是否为空,如果为空返回,若不为空,再检查下个结点的next[2]是否为空,如果为空返回
2. 字典树的应用
(1)用于查字符串的字典树:
用于查找字符串的字典树,输的结点结构体可以定义为:
struct node { bool isword; node *next[26]; };其中isword用于判断从根节点到此结点是否构成一个单词,next数组用于指示26个结点指针,这里假定所有单词都使用小写英文字母来表示。
# include <iostream> # include <cstdlib> # include <cstring> using namespace std; struct node { bool isword; node *next[26]; }; node *head=NULL; void insert(char s[]) { node *p=head; int len=strlen(s); int i=0; for(i=0;i<len;i++) { if(p->next[s[i]-'a']==NULL) { node *tmp=(node *)malloc(sizeof(node)); tmp->isword=false; int j=0; for(j=0;j<26;j++) tmp->next[j]=NULL; p->next[s[i]-'a']=tmp; p=tmp; } else p=p->next[s[i]-'a']; } p->isword=true; } int find(char *s) { node *p=head; if(p==NULL) return 0; while(p!=NULL&&*s!='\0') { if(p->next[(*s)-'a']){ p=p->next[(*s)-'a']; s++; } else return 0; } return (p!=NULL&&(*s)=='\0'&&p->isword==true); } void destroy(node *head) { if(head!=NULL){ int i; for(i=0;i<26;i++) { if(head->next[i]!=NULL) destroy(head->next[i]); } free(head); } } int main(void) { head=(node *)malloc(sizeof(node)); head->isword=false; int i=0; for(;i<26;i++) head->next[i]=NULL; char s1[20]="hello"; char s2[20]="world"; char s3[20]="hell"; insert(s2); insert(s1); cout<<find(s1)<<endl; destroy(head); system("pause"); return 0; }
(2)用于统计前缀出现次数的字典树
用于统计前缀出现次数的字典树,其树的结点结构体可以定义如下:
struct node { int num; node *next[26]; };其中num为这个本前缀出现的次数,next数组表示的含义与上面类似。
# include <iostream> # include <string> # include <cstdlib> using namespace std; struct node { int num; node *next[26]; }; node *head=0; int main() { char s[20]; void insert(char a[]); int find(char a[]); void destroy(node *head); int i; head=new node; for(i=0;i<26;i++) head->next[i]=NULL; cout<<"input words and terminate by '#'"<<endl; while(cin>>s&&s[0]!='#') { insert(s); } cout<<"input the prefix"<<endl; cin>>s; cout<<"the number is"<<endl; cout<<find(s)<<endl; destroy(head); system("pause"); return 0; } void insert(char a[]) { node *s=head; int i; int len=strlen(a); for(i=0;i<len;i++) { int k=a[i]-'a'; if(s->next[k]==NULL) { node *tmp=new node; tmp->num=1; int j=0; for(j=0;j<26;j++) tmp->next[j]=NULL; s->next[k]=tmp; s=s->next[k]; } else { s=s->next[k]; s->num++; } } } int find(char a[]) { int i; int len=strlen(a); int count=0; node *s=head; for(i=0;i<len;i++) { int k=a[i]-'a'; if(s->next[k]==NULL) {count=0; return count; } else { s=s->next[k]; count=s->num; } } return count; } void destroy(node *head) { if(head!=NULL){ int i; for(i=0;i<26;i++) { if(head->next[i]!=NULL) destroy(head->next[i]); } free(head); } }
(3)用于字符串排序的字典树
用于字符串排序的字典树,树的结点结构体可以定义如下:
struct node { int count; char *s; node *next[26]; };其中count用于保存某个字符串出现的次数,s用于保存到本节点为止的字符串,next数组含义与前面的类似。
# include <iostream> # include <cstdlib> # include <cstring> using namespace std; int cnt=0; struct node { int count; char *s; node *next[26]; }; node *head=NULL; void insert(char str[]) { node *p=head; int len=strlen(str); int i=0; for(;i<len;i++) { if(p->next[str[i]-'a']==NULL) { node *tmp=(node *)malloc(sizeof(node)); tmp->count=0; tmp->s=(char *)malloc(50*sizeof(char)); int j; for(j=0;j<26;j++) tmp->next[j]=NULL; strcpy(tmp->s,p->s); //strcat(tmp->s,p->s); //strcat(tmp->s,str[i]); //strcat(tmp->s,'\0'); char ctmp[2]={str[i],'\0'}; strcat(tmp->s,ctmp); p->next[str[i]-'a']=tmp; p=tmp; } else p=p->next[str[i]-'a']; } p->count++; } void sort(node *head,char **str) { if(head!=NULL) { if(head->count>0) { for(int i=0;i<head->count;i++) str[cnt++]=head->s; } for(int j=0;j<26;j++) sort(head->next[j],str); } } void destroy(node *head) { if(head!=NULL){ int i; for(i=0;i<26;i++) { if(head->next[i]!=NULL) destroy(head->next[i]); } free(head); } } int main(void) { head=(node *)malloc(sizeof(node)); int i=0; for(i=0;i<26;i++) head->next[i]=NULL; head->count=0; head->s=(char *)malloc(50*sizeof(char)); head->s[0]='\0'; char s1[20]="hello"; char s2[20]="world"; char s3[20]="helloa"; char *str[3]={s1,s2,s3}; insert(str[0]); insert(str[1]); insert(str[2]); sort(head,str); cout<<str[0]<<endl; cout<<str[1]<<endl; cout<<str[2]<<endl; destroy(head); system("pause"); return 0; }