本章知识摘自:http://blog.csdn.net/creatorx/article/details/71100840
主要是在trie树的基础上,添加fail指针。
实际上,在AC自动机中的trie树中的每个节点,维护的是一个后缀树,而对于一个节点i的fail指针所指向的节点j需满足:j为i的最优后缀(即i的最长的且存在的后缀)
先copy上一章所说的trie树的节点构造及插入过程。
struct node{
node* next[26];
node* fail;
int sum;
};
node* New(){
node*nod=(node*)malloc(sizeof(struct node));
rep(i,0,25)nod->next[i]=0;
nod->sum=0;nod->fail=0;
return nod;
}
node*root=New();
void Insert(char*s){
node*p=root;
int len=strlen(s);
rep(i,0,len-1){
int x=s[i]-'a';
if(p->next[x]==NULL)p->next[x]=New();
p=p->next[x];
}
p->sum++;
}
以下是构造fail指针的过程:
void getfail(){
queue<node*>q;//BFS思想
node*p=root;
rep(i,0,25){
if(p->next[i]){
q.push(p->next[i]);
p->next[i]->fail=root;
}
}
while(!q.empty()){
node*temp=q.front();q.pop();
rep(i,0,25){
if(temp->next[i]){
q.push(temp->next[i]);
p=temp->fail;//类似于KMP算法
while(p){
if(p->next[i]){
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(p==NULL)temp->next[i]->fail=root;
}
}
}
}
访问文本串时也是用KMP算法的思想:
int Find(char*s){
int len=strlen(s),tot=0;
node*p=root;
rep(i,0,len-1){
int x=s[i]-'a';
while(!p->next[x]&&p!=root)p=p->fail;//当前字符失配,则跳转至其最优后缀
p=p->next[x];
if(p==NULL)p=root;
node*temp=p;
while(temp!=root){//当前节点所代表的字符串在文本串中出现过,则其任意后缀也在文本串中出现过
if(temp->sum>=0){
tot+=temp->sum;
temp->sum=-1;//当前节点已经计过数,不再重复计数
}
else break;
temp=temp->fail;
}
}
return tot;//返回有多少个模式串在文本串中出现过
}