AC自動機步驟詳解

2021-07-04 12:51:54 字數 2924 閱讀 1539

ac自動機

求多個字串是否在主串中出現過。可依據情況分別求出出現次數,出現位置等。

要搞懂ac自動機,先得有模式樹(字典樹)trie和kmp模式匹配演算法的基礎知識。

1.構造一棵trie,作為ac自動機的搜尋資料結構。

2.構造fail指標,使當前字元失配時跳轉到具有最長公共前字尾的字元繼續匹配。如同 kmp演算法一樣, ac自動機在匹配時如果當前字元匹配失敗,那麼利用fail指標進行跳轉。由此可知如果跳轉,跳轉後的串的字首,必為跳轉前的模式串的字尾並且跳轉的新位置的深度(匹配字元個數)一定小於跳之前的節點。所以我們可以利用 bfs在 trie上面進行 fail指標的求解。

3.掃瞄主串進行匹配。

我們給出5個單詞,say,she,shr,he,her。給定字串為yasherhs。問多少個單詞在字串中出現過?

首先這個trie樹的每個節點必須包含以下元素:

1.乙個失敗指標,記錄匹配失敗後將要跳轉的節點。 **中的node *fail;

2.26個兒子節點,記錄的是26個兒子,編號代表下乙個字母的值。  **中的node *child[26];

3.乙個標記當前是不是乙個單詞的結尾。**中的int count;

4.順便呼叫構造方法給每個節點賦初值。

節點**:

struct node

};

然後開始建樹。trie樹教程點此。

建樹**:

void insert(node *t,char *p)

t->count=1;

}

root的失敗指標為null。

求某個節點的失敗指標的方法:

1.判斷他的父親節點是不是root。

2.若是,他的失敗指標指向的是root。

3.若不是,找到父親節點失敗指標所指的節點的子節點是否含有和所求節點相同的字母。例如,上圖中求she中e的失敗指標:e的父親節點h的失敗指標是her中的h,而h的兒子節點有和e相同的節點。

4.如果含有,失敗指標就是找到的那個和本節點相同的節點,如she中e的失敗指標就是he中的e節點。

5.如果沒有,找到他父親的失敗指標的失敗指標繼續3.。直到到root節點都沒找到的話,就令本解點的失敗指標為root。如shr的r節點,他的父親節點h的失敗指標是her中的h。其子節點中只有e,沒有r所以再求her中h的失敗指標,他是root,所以shr中r的失敗指標是root。

構建失敗指標部分**如下:

void ac(node *t)

tmp=tmp->fail;

}if(tmp==null)

temp->child[i]->fail=t;

}q.push(temp->child[i]);}}

}}

構造好trie和失敗指標後,我們就可以對主串進行掃瞄了。

這個過程和kmp演算法很類似,但是也有一定的區別,主要是因為ac自動機處理的是多串模式,需要防止遺漏某個單詞,所以引入temp指標。

匹配過程分兩種情況:

(1)當前字元匹配,表示從當前節點沿著樹邊有一條路徑可以到達目標字元,此時只需沿該路徑走向下乙個節點繼續匹配即可,目標字串指標移向下個字元繼續匹配;

(2)當前字元不匹配,則去當前節點失敗指標所指向的字元繼續匹配,匹配過程隨著指標指向root結束。重複這2個過程中的任意乙個,直到模式串走到結尾為止。

看一下模式匹配這個詳細的流程:

其中模式串為yasherhs。對於i=0,1。trie中沒有對應的路徑,故不做任何操作;

i=2,3,4時,指標p走到左下節點e。因為節點e的count資訊為1,所以cnt+1,並且講節點e的count值設定為-1,表示改單詞已經出現過了,防止重複計數。

最後temp指向e節點的失敗指標所指向的節點繼續查詢,以此類推,最後temp指向root,退出while迴圈。

這個過程中count增加了2。表示找到了2個單詞she和he。

當i=5時,程式進入第5行,p指向其失敗指標的節點,也就是右邊那個e節點,隨後在第6行指向r節點,r節點的count值為1,從而count+1,迴圈直到temp指向root為止。

最後i=6,7時,找不到任何匹配,匹配過程結束。

**如下:

int query(node *t,char *p)

}p++;

}return cnt;

}void del(node *root)

#include #include #include using namespace std;

struct node

};char s1[51];

char s2[1000001];

queue q;

void insert(node *t,char *p)

t->count=1;

}void ac(node *t)

tmp=tmp->fail;

}if(tmp==null)

temp->child[i]->fail=t;

}q.push(temp->child[i]);}}

}}int query(node *t,char *p)

}p++;

}return cnt;

}void del(node *root)

int main()

gets(s2);

ac(root);

printf("%d\n",query(root,s2));

del(root);

}return 0;

}

AC自動機詳解

最近真是太頹了,做了一堆板子題,現在對一些知識點順便來個總結記錄 大家應該都知道kmp和trie樹吧,不懂的可以看我部落格或到網上自己動手尋找資料。ac自動機是乙個很好的東西,這是因為它的名字很好它能夠在有多個模式串的時候進行全文匹配,這十分方便地擴充套件了kmp的功能,實際上它的思路與原理與kmp...

AC自動機詳解

首先,ac自動機,不是 自動accepted機,這是乙個多模字串匹配演算法,學習這個演算法,首先要熟悉kmp演算法這個單模字串匹配演算法,然後,我們知道有個高效的多模字串匹配演算法,叫字典樹,它處理的是一些單詞在乙個句子裡出現了幾次,但假如不是在乙個句子裡,而是在乙個字串裡呢?那它就顯得很弱了,所以...

AC自動機詳解

include include include include include include include include using namespace std typedef long long ll const int maxn 2 1e6 9 int trie maxn 26 字典樹 i...