zoukankan      html  css  js  c++  java
  • 【暑假】[实用数据结构] AC自动机

    Aho-Corasick自动机

     算法:

     <功能>

      AC自动机用于解决文本一个而模板有多个的问题。

      AC自动机可以成功将多模板匹配,匹配意味着算法可以找到每一个模板在文本中出现的位置。

     <解释>

      KMP中对模板构造失配边,多模板每条模板独立构造失配边太过麻烦。

      算法利用Trie+KMP中的失配边。insert(模板) 构造Trie+ getFail添加失配边->AC自动机的状态转移图。

      匹配文本串text时只需要调用find,find依次匹配text中的每一个字符失败则沿着失配边走,在匹配路径上如果遇到单词结点(val != 0 )即相当于匹配成功。

      但需要注意到:可能有作为当前后缀的单词已经成功匹配,所以需要加入后缀链接last[] 在每一个结点都要处理这种情况。last递推得到。

    作者所给模板如下

     1 struct AhoCorasickAutomata {
     2   int ch[MAXNODE][SIGMA_SIZE];
     3   int f[MAXNODE];    // fail函数
     4   int val[MAXNODE];  // 每个字符串的结尾结点都有一个非0的val
     5   int last[MAXNODE]; // 输出链表的下一个结点
     6   int cnt[MAXS];
     7   int sz;
     8 
     9   void init() {
    10     sz = 1;
    11     memset(ch[0], 0, sizeof(ch[0]));
    12     memset(cnt, 0, sizeof(cnt));
    13     ms.clear();
    14   }
    15 
    16   // 字符c的编号
    17   int idx(char c) {
    18     return c-'a';
    19   }
    20 
    21   // 插入字符串 v必须非0
    22   void insert(char *s, int v) {
    23     int u = 0, n = strlen(s);
    24     for(int i = 0; i < n; i++) {
    25       int c = idx(s[i]);
    26       if(!ch[u][c]) {
    27         memset(ch[sz], 0, sizeof(ch[sz]));
    28         val[sz] = 0;
    29         ch[u][c] = sz++;
    30       }
    31       u = ch[u][c];
    32     }
    33     val[u] = v;
    34     ms[string(s)] = v;
    35   }
    36 
    37   // 递归打印以结点j结尾的所有字符串
    38   void print(int j) {
    39     if(j) {
    40       cnt[val[j]]++;
    41       print(last[j]);
    42     }
    43   }
    44 
    45   // 在T中找模板
    46   int find(char* T) {
    47     int n = strlen(T);
    48     int j = 0; // 当前结点编号 初始为根结点
    49     for(int i = 0; i < n; i++) { // 文本串当前指针
    50       int c = idx(T[i]);
    51       while(j && !ch[j][c]) j = f[j]; // 顺着细边走 直到可以匹配
    52       j = ch[j][c];
    53       if(val[j]) print(j);
    54       else if(last[j]) print(last[j]); // 找到了 
    55     }
    56   }
    57 
    58   // 计算fail函数
    59   void getFail() {
    60     queue<int> q;
    61     f[0] = 0;
    62     // 初始化队列
    63     for(int c = 0; c < SIGMA_SIZE; c++) {
    64       int u = ch[0][c];
    65       if(u) { f[u] = 0; q.push(u); last[u] = 0; }
    66     }
    67     // 按BFS顺序计算fail
    68     while(!q.empty()) {
    69       int r = q.front(); q.pop();
    70       for(int c = 0; c < SIGMA_SIZE; c++) {
    71         int u = ch[r][c];
    72         if(!u) continue;
    73         q.push(u);
    74         int v = f[r];
    75         while(v && !ch[v][c]) v = f[v];
    76         f[u] = ch[v][c];
    77         last[u] = val[f[u]] ? f[u] : last[f[u]];
    78       }
    79     }
    80   }
    81 
    82 };
  • 相关阅读:
    百度文库文档下载分析
    旅游公司招聘Java工程师
    C# 在Repeater 的ItemDataBound 如何转换e.Item.DataItem 的类型
    IOS多线程GCD
    vDSP加速的应用
    ios获取内核数目
    Struts06---通配符的使用
    Struts05---动态查询
    Struts04---命名空间的查询顺序以及默认执行的Action
    Struts03---参数传递
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4719186.html
Copyright © 2011-2022 走看看