過程
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指針的這個子節點
}
}
}