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;
}