首页 > 代码库 > trie树(字典树)

trie树(字典树)

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