AC自动机是基于KMP思想和字典树的一种数据结构,是用来处理多模式匹配的。
至于详细的解释百度很多博客有。
我就记录一下模板
构造字典树
const int kind = 26;
struct node
{
node *fail; //失败指针
node *next[kind]; //Tire每个节点的个子节点(最多个字母)
int count; //是否为该单词的最后一个节点
node()
{ //构造函数初始化
fail = NULL;
count = 0;
memset(next, NULL, sizeof(next));
}
} *q[500001]; //队列,方便用于bfs构造失败指针
char keyword[51]; //输入的单词
char str[1000001]; //模式串
int head,tail; //队列的头尾指针
插入数组
void insert(char *str) //建立Trie
{
int temp, len;
node *p = root;
len = strlen(str);
for(int i = 0; i < len; ++i)
{
temp = str[i] - 'a';
if(p->next[temp] == NULL)
p->next[temp] = new node();
p = p->next[temp];
}
p->count++;
}
构造自动机
void build_ac_automation(node *root)
{
head = tail = 0;//应该是这样吧
int i;
root->fail = NULL;
q[head++] = root;
while (head != tail)
{
node *temp = q[tail++];//当前指向的结点
node *p = NULL;
for (i = 0; i < 26; i++)
{
if (temp->next[i] != NULL)
{
if (temp == root) temp->next[i]->fail = root;//表示直接与root相连的结点
else
{
p = temp->fail;
while (p != NULL)//不断通过fali指针往上找
{
if (p->next[i] != NULL) //表示该节点存在一个与当前字母相同的儿子
{
temp->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if (p == NULL) temp->next[i]->fail = root;//如果找到根节点了就指向根节点
}
q[head++] = temp->next[i];
}
}
}
}
查询
int query(node *root)
{
int i = 0, cnt = 0, index, len = strlen(str);
node *p = root;
while (str[i])
{
index = str[i] - 'a';
while (p->next[index] == NULL && p != root) p = p->fail;
p = p->next[index];
p = (p == NULL) ? root : p;
node *temp = p;
while (temp != root && temp->count != -1)
{
cnt += temp->count;
temp->count = -1;
temp = temp->fail;
}
i++;
}
return cnt;
}
(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。
代码等转载自http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
关于字典树的模板我可能更喜欢用kuangbin的,下次再说吧