过程
fail指针可以说是AC自动机里最难理解的东西,怎样更好的理解AC自动机的fail指针?
先来看一幅图:
看这幅图上的fail指针是怎么构造的.
树上的词分别是:
{he,hers,his,she}
按图所示分成3层。看到第三层,是"she",其中:
下面以"she"创建fail指针的过程为例
-
s指向root
-
h先找到s的fail指针
发现是0号指针,不是h,然后h就不高兴了,再问问s的fail指针root:“你有没有儿子和我同名叫h的”
root说:“有,你指向他吧”,然后h就高兴的指向了第一行的h.
- e开始找了
首先问他老爸h:“你的fail指针指着谁”
h说:“图上第一行那个h啊”
然后e就屁颠屁颠地跑去问图上第一行那个h:“你有没有名字和我一样的儿子啊”
图上第一行那个h说:“有,他地址是xxx”
最后e的fail指针就指向xxx地址,也就是第一行那个e了
- 作用
发现这样,如果一个字符串查到第三行的e以后的字符才不匹配,那说明他前面应该有个‘he’
刚好e的失败指针指向的是第一行的‘he...’的那个e;
这样就不用从h开始再找一遍,而是接着第一行的e继续往后找,从而节省了时间.
(code)
void get_fail()
{
queue<int>q;
for(int i=0;i<26;++i){//提前处理第二层的fail指针
if(ac[0].vis[i]!=0)
{
ac[ac[0].vis[i]].fail=0;//指向根节点
q.push(ac[0].vis[i]);
}
}
while(!q.empty())//bfs求fail指针
{
int u=q.front();
q.pop();
for(int i=0;i<26;++i)
{
if(ac[u].vis[i])//存在这个节点
{
ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];
//子节点的fail指针指向当前节点的
//fail指针所指向的节点的相同子节点
q.push(ac[u].vis[i]);
}
else
ac[u].vis[i]=ac[ac[u].fail].vis[i];
//当前节点的这个子节点指向当
//前节点fail指针的这个子节点
}
}
}