AC算法原理与实现(模式匹配)

本文详细介绍Aho-Corasick自动机匹配算法,包括Trie树构建、失败指针构造及模式匹配过程。并提供完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学习模式匹配知识,了解了KMP与BM算法后,AC的了解也必不可少。上网学习了下,把重要的知识总结一下。
Aho_Corasick自动机匹配算法是最著名的多模式匹配算法之一。 AC自动机算法分为3步:构造一颗Trie树,构造失败指针和模式匹配过程。
1.建立一颗Trie的过程比较简单(可参考源代码)
2.构造失败指针
构造失败指针的过程概括起来就一句话:设这个节点上的字母为 C ,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为 C 的节点。然后把当前节点的失败指针指向那个字母也为 C 的儿子。如果一直走到了 root 都没找到,那就把失败指针指向 root
3.模式匹配过程
匹配过程分两种情况:
(1) 当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
(2) 当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,匹配过程随着指针指向root 结束
下面给出AC算法的具体C++实现:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1000001; //模式串的最大长度MAXN - 1
const int MAXM = 51; //单词最大长度为MAXM - 1
const int KEYSIZE = 26; //26个小写字母
struct Node {
      Node *fail;  //失败指针
      Node *next[KEYSIZE]; //儿子结点个数
      int count; //单词个数
      Node() {
            fail = NULL;
            count = 0;
            memset(next, 0, sizeof(next));
      }
}*q[MAXN / 2];
void insert(char *str, Node *root)
{
      Node *p = root;
      int i = 0;
      while(str[i]) {
           int index = str[i] - 'a';
           if(p -> next[index] == NULL)
                  p -> next[index] = new Node();
           p = p -> next[index];
           i ++;
      }
      p -> count ++; //在单词的最后一个结点count + 1,代表一个单词
}
void build_ac_automation(Node *root)
{
      root -> fail = NULL;
      int head, tail;
      head = tail = 0;
      q[tail ++] = root;
      while(head < tail) {
            Node *temp = q[head ++];
            for(int i = 0; i < KEYSIZE; i ++) {
                if(temp -> next[i] != NULL) {
                     if(temp == root) {
                          temp -> next[i] -> fail = root;
                     }else {
                          Node *p = temp -> fail;
                          while(p != NULL) {
                               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[tail ++] = temp -> next[i];
                }
           }
      }
}
int AC_search(char *str, Node *root)
{
      int i = 0, cnt = 0;
      Node *p = root;
      while(str[i]) {
           int 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;
}
int main()
{
      int n;
      Node *root;
      char keyword[MAXM]; //单词
      char str[MAXN]; //模式串
   printf("scanf the number of words-->/n");
      scanf("%d", &n);
      root = new Node();
   printf("scanf the words-->/n");
      while(n --) {
  scanf("%s", keyword);
  insert(keyword, root);
      }
      build_ac_automation(root);
   printf("scanf the text-->/n");
      scanf("%s", str);
      printf("there are %d words match/n", AC_search(str, root));
     
      return(0);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值