AC自動機多模匹配算法 C++實現
相關內容
AC自動機
Aho-Corasick automaton,是一種多模板匹配算法,基於Trie樹和KMP算法,查找操作與Trie類似,與Trie不同的是,AC自動機查找過程中失配時,到當前失配結點fail指針指向的結點繼續查找,fail指針指向當前最結尾字符串的最長後綴子串,每次遇到一個結點檢測其是否爲單詞的尾結點,若是則輸出該節點,若失配則還要檢測fail指針指向的結點是否爲某個單詞的尾結點,失配後轉向最長後綴的下一個結點,保證t串不用回溯
Fail數組
其中getFail()函數的else語句中的letters[currentLevel][i] = letters[fail[currentLevel]][i];
,方便了search()函數中向下查找的操作,即currentLevel = letters[currentLevel][letter];
void AhoCorasickAutomaton::getFail() {
// 以BFS順序計算fail數組指向的結點
queue<int> q;
fail[0] = 0;
// 將第0行出現的所有結點入隊
for (int i = 0; i < SIGMA_SIZE; i++) {
int letter = letters[0][i];
if (letter) {
fail[letter] = 0;
q.push(letter);
}
}
while (!q.empty()) {
// 隊首元素作爲當前字母對應層
int currentLevel = q.front();
q.pop();
for (int i = 0; i < SIGMA_SIZE; i++) {
// 對於當前字母結點的所有子結點
int letter = letters[currentLevel][i];
if (letter) {
// 將存在的結點對應層入隊,求解其孩子結點(若存在)的fail指針
q.push(letter);
// 若子節點存在,則其fail指針指向其父結點對應fail指向結點的對應子節點
// 若以其當前結點爲結尾的字符串存在大於1的最長後綴兩種情況
// 當前結點若在其父結點的fail指向結點的子節點中也存在,則以當前結點爲最長後綴的長度加1,並將fail指針指向它
// 當前結點若在其父結點的fail指向結點的子節點中不存在,則fail指針指向個根節點0
fail[letter] = letters[fail[currentLevel]][i];
} else {
// 爲方便查找操作
// 若不存在,當前孩子結點則置爲父結點的fail指針的對應孩子結點
// 若對應孩子節點存在,則直接跳轉到對應結點處即可
// 若不存在, 則爲0,跳轉到根節點
letters[currentLevel][i] = letters[fail[currentLevel]][i];
}
}
}
}
查找操作
void AhoCorasickAutomaton::search(string t) {
int currentLevel = 0;
for (int i = 0; i < t.size(); i++) {
int letter = index(t[i]);
// 向下搜索直到遍歷整個t字符串
// 若存在對應結點則繼續向下,否則跳轉到對應fail指針
// 如上述getFail()函數所述
// getFail()函數的else語句中已經將不存在的結點值置爲對應fail指針的值
currentLevel = letters[currentLevel][letter];
// 打印單詞
if (tag[currentLevel]) {
cout << information[currentLevel] << endl;
}
if (tag[fail[currentLevel]]) {
cout << information[fail[currentLevel]] << endl;
}
}
}
樣例圖解
綠色箭頭指向結點fail指針對應值,紅色結點代表單詞的尾結點
實現代碼
/*
author : eclipse
email : [email protected]
time : Sun Jun 14 21:51:51 2020
*/
#include <bits/stdc++.h>
using namespace std;
class AhoCorasickAutomaton {
private:
static const int MAX_SIZE = 1024;
static const int SIGMA_SIZE = 26;
vector<vector<int> > letters;
vector<string> information;
int size;
vector<bool> tag;
vector<int> fail;
int index(char c);
public:
AhoCorasickAutomaton(vector<string> words);
void insert(string str);
void search(string str);
void getFail();
};
AhoCorasickAutomaton::AhoCorasickAutomaton(vector<string> words) {
size = 0;
fail.resize(MAX_SIZE);
tag.resize(MAX_SIZE);
information.resize(MAX_SIZE);
letters.resize(MAX_SIZE);
for (int i = 0; i < MAX_SIZE; i++) {
letters[i].resize(SIGMA_SIZE);
}
for (int i = 0; i < SIGMA_SIZE; i++) {
letters[0][i] = 0;
}
for (int i = 0; i < words.size(); i++) {
insert(words[i]);
}
getFail();
}
int AhoCorasickAutomaton::index(char c) {
return c - 'a';
}
void AhoCorasickAutomaton::insert(string str) {
int currentLevel = 0;
for (int i = 0; i < str.size(); i++) {
int letter = index(str[i]);
if (!letters[currentLevel][letter]) {
for (int j = 0; j < SIGMA_SIZE; j++) {
letters[size][j] = 0;
}
tag[size] = false;
letters[currentLevel][letter] = size++;
}
currentLevel = letters[currentLevel][letter];
}
tag[currentLevel] = true;
information[currentLevel] = str;
}
void AhoCorasickAutomaton::getFail() {
queue<int> q;
fail[0] = 0;
for (int i = 0; i < SIGMA_SIZE; i++) {
int letter = letters[0][i];
if (letter) {
fail[letter] = 0;
q.push(letter);
}
}
while (!q.empty()) {
int currentLevel = q.front();
q.pop();
for (int i = 0; i < SIGMA_SIZE; i++) {
int letter = letters[currentLevel][i];
if (letter) {
q.push(letter);
fail[letter] = letters[fail[currentLevel]][i];
} else {
letters[currentLevel][i] = letters[fail[currentLevel]][i];
}
}
}
}
void AhoCorasickAutomaton::search(string t) {
int currentLevel = 0;
for (int i = 0; i < t.size(); i++) {
int letter = index(t[i]);
currentLevel = letters[currentLevel][letter];
if (tag[currentLevel]) {
cout << information[currentLevel] << endl;
}
if (tag[fail[currentLevel]]) {
cout << information[fail[currentLevel]] << endl;
}
}
}
int main(int argc, char const *argv[]) {
vector<string> words;
int N;
scanf("%d", &N);
words.resize(N);
for (int i = 0; i < N; i++) {
cin >> words[i];
}
AhoCorasickAutomaton *ahoCorasickAutomaton = new AhoCorasickAutomaton(words);
string t;
cin >> t;
ahoCorasickAutomaton->search(t);
return 0;
}
輸入數據
6
his
hers
her
him
he
she
shers
輸出結果
she
he
her
hers
鳴謝
最後
- 由於博主水平有限,不免有疏漏之處,歡迎讀者隨時批評指正,以免造成不必要的誤解!