字典树
1.创建
struct Trie
{
// 代表当前节点可以延伸出的边,数量可变
Trie *Next[MAXN];
// 标记当前节点是否是保存信息的结尾,也可以代表前缀个数
int Flag;
Trie()
{
// 初始化以该信息为前缀的信息个数
Flag = 1;
memset(Next, NULL, sizeof(Next));
}
}*root;
2.插入
void Insert(char *str) {
int len = strlen(str);
Trie *p = root, *q;
// 将str的每一个字符插入trie树
for(int i=0; i<len; ++i) {
int id = str[i] - 'a';
// 如果没有边,则新建一个trie节点,产生一条边,用以代表该字符
if(p->Next[id] == NULL) {
q = new Trie();
p->Next[id] = q;
p = p->Next[id]; }
// 如果存在边,则沿着该边走
else {
p = p->Next[id];
// 累加以该信息为前缀的信息个数
++(p->Flag); } } }
3.查找
int Query(char *str)
{
int len = strlen(str);
Trie *p = root;
// 在trie树上顺序搜索str的每一个字符
for(int i=0; i<len; ++i)
{
int id = str[i] - 'a';
p = p->Next[id];
// 若为空集,表示不存以此为前缀的信息
if(p == NULL) return 0;
}
// 返回以该信息为前缀的信息个数
return p->Flag;
}
4.删除
void Free(Trie* T)
{
if(T == NULL) return;
// 释放trie树的每一个节点占用的内存
for(int i=0; i<MAXN; ++i)
{
if(T->Next[i]) Free(T->Next[i]);
}
delete(T);
}
例 1 hdu 1247
Hat’s Words
题意: 给出多个按字典序的单词,输出字典序 的符合要求的单词,要求为该单词可以由两个已有的单词拼成,即前缀和后缀都为已知单词
代码
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 26
struct Trie
{
Trie *Next[MAXN];
bool tf;
}*root;
char s[50000][50];
void Insert(char* str)
{
int len = strlen(str);
Trie*p = root, *q;
for (int i = 0; i<len; i++)
{
int id = str[i] - 'a';
if (p->Next[id] == NULL)
{
q = new Trie();
for(int j=0;j<MAXN;j++)
{
q->Next[j]=NULL;
}
q->tf=false;
p->Next[id] = q;
p = p->Next[id];
}
else
{
p = p->Next[id];
}
}
p->tf=true;
}
bool Querry(char* str)
{
int len = strlen(str);
Trie *p = root;
for (int i = 0; i<len; i++)
{
int id = str[i] - 'a';
p = p->Next[id];
if (p == NULL)
return false;
}
return p->tf;
}
void Free(Trie *T)
{
if (T == NULL)
return;
for (int i = 0; i<MAXN; i++)
{
if (T->Next[i])
Free(T->Next[i]);
}
delete(T);
}
int main()
{
int coun=0,i,j;
root = new Trie;
for(i=0;i<MAXN;i++)
{
root->Next[i]=NULL;
}
root->tf=false;
while(scanf("%s",s[coun])!=EOF)
{
Insert(s[coun]);
coun++;
}
for(i=0;i<coun;i++)
{
char temp1[50]={'\0'};
char temp2[50]={'\0'};
for(j=1;j<strlen(s[i]);j++)
{
strcpy(temp1,s[i]);
temp1[j]='\0';
strcpy(temp2,s[i]+j);
if(Querry(temp1)&&Querry(temp2))
{
printf("%s\n",s[i]);
break;
}
}
}
Free(root);
return 0;
}
例 2 hdu 1251 统计难题
题意: 输入多个单词 ,再输入一些前缀,输出 有该前缀的单词个数 。纯字典树 ,套模板
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
#define MAXN 26
struct Trie
{
Trie *Next[MAXN];
int Flag;
Trie()
{
memset(Next,NULL,sizeof(Next));
Flag=1;
}
}*root;
void Insert(char* str)
{
int len = strlen(str);
Trie*p = root, *q;
for (int i = 0; i<len; i++)
{
int id = str[i] - 'a';
if (p->Next[id] == NULL)
{
q = new Trie();
p->Next[id] = q;
p = p->Next[id];
}
else
{
p = p->Next[id];
++(p->Flag);
}
}
}
int Querry(char* str)
{
int len = strlen(str);
Trie *p = root;
for (int i = 0; i<len; i++)
{
int id = str[i] - 'a';
p = p->Next[id];
if (p == NULL)
return 0;
}
return p->Flag;
}
void Free(Trie *T)
{
if (T == NULL)
return;
for (int i = 0; i<MAXN; i++)
{
if (T->Next[i])
Free(T->Next[i]);
}
delete(T);
}
int main()
{
root = new Trie;
char a[11];
while(gets(a)&&a[0])
{
Insert(a);
}
while(gets(a))
{
cout<<Querry(a)<<endl;
}
Free(root);
return 0;
}