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 : eclipsecs@qq.com
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
鸣谢
最后
- 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!