字典树算法
上面的KMP是一对一匹配的时候常用的算法。而字典树则是一对多的时候匹配常用算法。其含义是,把一系列的模板串放到一个树里面,然后每个节点存的是它自己的字符,从根节点开始往下遍历就可以得到一个个单词了。
(图片来自百度)
我这里写的代码稍微和上面有一点区别,我的节点tnode里面没有存它本身的字符,而是存一个孩子数组。所以当数据量很大的时候还是需要做一些变通的,不可直接套用此代码。若是想以每个节点为一个node,那么要注意根节点是空的。
树的节点tnode,这里的next[i]存的是子节点指针。sum=0表示这个点不是重点。为n>0表示有n个单词以此为终点。
struct Dictree{
int cnt[N];
int tree[N][30];
int tot=0;
void Insert(char *s){
int len = strlen(s);
int now = 0;
for(int i=0;i<len;i++){
int id = s[i] - 'a';
if(!tree[now][id])
tree[now][id] = ++tot;
now = tree[now][id];
cnt[now]++;
}
}
int Search(char *s){
int len = strlen(s);
int now = 0;
for(int i=0;i<len;i++){
int id = s[i] - 'a';
if(!tree[now][id])
return 0;
now = tree[now][id];
}
return cnt[now];
}
}dictree;
指针:
#include<queue>
#include<set>
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
/*
trie字典树
*/
struct tnode{
int sum;//用来判断是否是终点的
tnode* next[26];
tnode()
{
for(int i =0;i<26;i++)
next[i]=NULL;
sum=0;
}
};
tnode *root;
tnode* newnode(){
tnode *p = new tnode;
for(int i =0;i<26;i++)
p->next[i]=NULL;
p->sum=0;
return p;
}
//插入函数
void Insert(char *s)
{
tnode *p = root;
for(int i = 0 ; s[i] ; i++)
{
int x = s[i] - 'a';
if(p->next[x]==NULL)
{
tnode *nn=newnode();
for(int j=0;j<26;j++)
nn->next[j] = NULL;
nn->sum = 0;
p->next[x]=nn;
}
p = p->next[x];
}
p->sum++;//这个单词终止啦
}
//匹配函数
bool Compare(char *ch)
{
tnode *p = root;
int len = strlen(ch);
for(int i = 0; i < len; i++)
{
int x = ch[i] - 'a';
p = p->next[x];
if(p==NULL)
return false;
if(i==len-1 && p->sum>0 )
{
return true;
}
}
return false;
}
void DELETE(tnode * &top){
if(top==NULL)
return;
for(int i =0;i<26;i++)
DELETE(top->next[i]);
delete top;
}
int main()
{
int n,m;
cin>>n;
char s[20];
root = newnode();
for(int i =0;i<n;i++){
scanf("%s",s);
Insert(s);
}
cin>>m;
for(int i =0;i<m;i++){
scanf("%s",s);
if(Compare(s))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
DELETE(root);//看见指针就要想到释放,然而这东西会花时间,所以网上很多人写ACM题就不delete了,我很看不惯这一点。
return 0;
}
转载:https://blog.csdn.net/qq_30346729/article/details/78835040