AC自动机
- 什么是多模匹配问题?
有多个模式串的匹配问题,就是多模匹配问题 - 处理方法
- 多个模式串,建立成一棵字典树
- 和文本串的每一位对齐匹配,模拟暴力匹配算法的过程
常规多模匹配
从文本串中的每一次在字典树中看是否有可以匹配的
当匹配成功文本串中的she时,也就意味着后续一定会匹配成功he she对应了字典树中的节点P,he对应了字典树中的节点Q
P和Q就是等价匹配节点,如果从P引出一条边指向Q,就可以加速匹配过程 在P下面查找节点的操作,等价于在Q下面查找节点的操作
这条等价关系边,通常在AC自动上叫做 : FAIL指针 AC自动机 = Trie + Fail指针
子节点的Fail指针需要参照父节点的Fail指针信息的,最近但的建立方式采用层序遍历
如何建立
在she中有两个节点可以建立等价边,一个是she中的h节点,一个是e节点
h节点匹配到根节点下的h
e节点匹配到根节点下h下的e,
相当于一个一一映射
建立子节点的等价关系,可以通过其父节点的等价关系
上图完全的等价匹配关系
建立方法:层序遍历建立:只有建立好上一层,才可以进行下一层建立
代码演示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
#define BASE 26
typedef struct Node {
int flag;
const char *str;
struct Node *next[BASE], *fail;
} Node;
int node_cnt = 0;
Node *getNewNode() {
node_cnt++;
Node *p = (Node *)malloc(sizeof(Node));
p->flag = 0;
memset(p->next, 0, sizeof(p->next));
p->fail = NULL;
return p;
}
void insert(Node *root, const char *str) {
for (int i = 0; str[i]; i++) {
int ind = str[i] - 'a';
if (root->next[ind] == NULL) root->next[ind] = getNewNode();
root = root->next[ind];
}
root->flag = 1;
root->str = strdup(str);
return ;
}
void build_ac(Node *root) {
Node **q = (Node **)malloc(sizeof(Node *) * (node_cnt + 5));//建立一个队列
int head = 0, tail = 0;//首尾指针
root->fail = NULL;//根节点没有fail指针
for (int i = 0; i < BASE; i++) {
if (root->next[i] == NULL) continue;
root->next[i]->fail = root;
q[tail++] = root->next[i];
}
while (head < tail) {
Node *p = q[head++];//取出队首元素
for (int i = 0; i < BASE; i++) {
//遍历该元素的所有子孩子
Node *c = p->next[i], *k = p->fail;//c为该节点的子孩子,子节点的fail 指针需要依靠根节点进行
if (c == NULL) continue;//没有该节点
while (k && k->next[i] == NULL) k = k->fail;//当根节点有fail指针,但是k节点没有第i个子孩子,,接着向上找
if (k == NULL) k = root;//如果k最终结果是空,那么a该节点的fail指针指向根节点
if (k->next[i]) k = k->next[i];//如果找到了,k的next[i]就是该节点的fail
c->fail = k;
q[tail++] = c;//放入该节点
}
}
free(q);
return ;
}
void match(Node *root, const char *text) {
Node *p = root, *q;