Trie树的基本实现
字母树的插入(Insert)、删除( Delete)和查找(Find)都非常简单,用一个一重循环即可,即第i 次循环找到前i 个字母所对应的子树,然后进行相应的操作。实现这棵字母树,我们用最常见的数组保存(静态开辟内存)即可,当然也可以开动态的指针类型(动态开辟内存)。至于结点对儿子的指向,一般有三种方法:
1、对每个结点开一个字母集大小的数组,对应的下标是儿子所表示的字母,内容则是这个儿子对应在大数组上的位置,即标号;
2、对每个结点挂一个链表,按一定顺序记录每个儿子是谁;
3、使用左儿子右兄弟表示法记录这棵树。
三种方法,各有特点。第一种易实现,但实际的空间要求较大;第二种,较易实现,空间要求相对较小,但比较费时;第三种,空间要求最小,但相对费时且不易写。
这里采用第一种,速度较快,适合ACM竞赛。
孩子数组大小自定义,此处默认为字母数26;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
typedef struct Trie
{
int nCount; //该节点前缀 出现的次数
struct Trie *next[26]; //孩子结点
}Trie;
Trie Memory[1000000]; //先分配内存 malloc费时间
int allocp = 0;
//初始化节点。nCount计数为1,next都是为NULL
Trie * InitNode()
{
Trie * tmp = &Memory[allocp++];
tmp->nCount = 1;
for(int i=0;i<26;i++)
tmp->next[i]=NULL;
return tmp;
}
void insertTrie(Trie * * pRoot, char * str)
{
Trie * tmp = *pRoot;
int i=0,k;
//逐个插入
while(str[i])
{
k=str[i]-'a';
if(tmp->next[k])
{
tmp->next[k]->nCount++;
}else
{
tmp->next[k]=InitNode();
}
tmp = tmp->next[k];
i++;
}
}
int searchTrie(Trie *root,char *str)
{
if(root==NULL)
return 0;
Trie *tmp = root;
int i=0,k;
while(str[i])
{
k=str[i]-'a';
if(tmp->next[k])
{
tmp = tmp->next[k];
}else
{
return 0;
}
i++;
}
return tmp->nCount; //返回最后那个结点保存的ncount
}
int main()
{
int m,n;
char s[11];
Trie * root = InitNode();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",s);
insertTrie(&root,s);
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%s",s);
printf("%d\n",searchTrie(root,s));
}
return 0;
}