Trie树是在查询问题中以空间换取时间的做法,时间复杂度为O(n),所以存在空间的大量消耗。
本文Trie树的应用便是查询某个词缀在字典中出现的频率。
Trie树的性质本文总结如下:
1:根节点不存储任何字符;
2:以某一个字符串结束标志节点为止,根节点至该节点所构成的路径内所有节点字符顺序构成一个字符串
3:节点的所有子节点应包含不同的字符
本文Trie树创建及查询:
1:为方便查询词缀出现频率,在每一个节点中包含以根节点至该节点所构成词缀的出现次数(及完成子节点创建或不为NULL及重复字符串);
2:节点中应包含字符串结束标志,在本文中使用true,false判断,亦可为根加显现的表示,可定义颜色字符串值(white/black)表示
3:在本文中重复单词也算不同单词计算频率(做过的一道ACM题中出现,所以本文中代码也将重复单词作为不同单词处理,当然在实际应用中,为避免重复单词的插入,在插入之前可进行查询操作,避免重复插入)
问题描述如下:
输入的第一行为一个正整数n,表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦),单词由不超过10个的小写英文字母组 成,可能存在相同的单词,此时应将其视作不同的单词。接下来的一行为一个正整数m,表示询问的次数,其后m行,每一行一个字符串,该字符串由不超过10个的小写英文字母组成,表示一个询问。
输出:
对于每一个询问,输出一个整数Ans,表示词典中给出的字符串为前缀的单词的个数。
本文查询思路:
接收到查询词缀,从根节点开始,循环查询,若在Trie树中不存在该词缀,返回0,若有,继续查询下一字符,直至词缀结束,返回此时所在节点的统计频率值。
简单实现代码如下:
#include <stdio.h>
#include <stdlib.h>
#define false 0
#define true 1
typedef struct Trie_node{
int count;
struct Trie_node* Trie_node_next[26];
int IsWord;
} TrieNode, *Trie;
Trie Trie_Create()
{
Trie Trie_new=(Trie)malloc(sizeof(TrieNode));
Trie_new->count=0;
Trie_new->IsWord=false;
int i;
for(i=0;i<26;i++)
Trie_new->Trie_node_next[i]=NULL;
return Trie_new;
}
void Trie_Insert(Trie root,char* word)
{
Trie node=root;
char *p=word;
int id;
while(*p)
{
id=*p-'a';
if(node->Trie_node_next[id]==NULL)
{
node->Trie_node_next[id]=Trie_Create();
}
node=node->Trie_node_next[id];
node->count+=1;
++p;
}
node->IsWord=true;
}
int Trie_Search(Trie root, char* word)
{
Trie node=root;
char *p=word;
int id;
while(*p)
{
id=*p-'a';
if(node->Trie_node_next[id]==NULL)
return 0;
node=node->Trie_node_next[id];
++p;
}
return node->count;
}
int main()
{
Trie Root=Trie_Create();
int m,n,i;
char word[10000],search[10000];
int count;
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%s",word);
Trie_Insert(Root,word);
}
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",search);
count=Trie_Search(Root,search);
printf("%d\n",count);
}
return 0;
}
程序运行结果如下: