AC自动机

AC自动机算法算是比较简单直观的字符串匹配自动机,它其实就是在一颗Trie树上建一些失配指针,当失配时只要顺着失配指针走,就能避免一些重复的计算。比如对于字符串antibody和tide,如果第一个串匹配到第5个字符(b)失配了可以直接走入第二个串的第3个字符(d)进行匹配,因为前面的“ti”是公共的,如果能匹配到第一个串的第5个字符,那么前面两个肯定是ti。[
Aho-Corasick自动机浅析
AC自动机算法详解

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1E5, MAXC = 26;

struct node
{
    node * fail;
    node * nxt[26];
    int id;
    node()
    {
        fail = nullptr;
        fill(nxt, nxt+MAXC, nullptr);
        id = -1;
    }
};

char keyword[100], s[MAXN];

void insert(const char *s, int id, node *root)
{
    node *p = root;
    for(int i=0; s[i]!='\0'; ++i)
    {
        if(p->nxt[s[i]-'a'] == nullptr) p->nxt[s[i]-'a'] = new node;
        p = p->nxt[s[i]-'a'];
    }
    p->id = id;
}

void build_fail_point(node * root)
{
    root->fail = nullptr;
    queue<node*> que;
    que.push(root);
    while(!que.empty())
    {
        node * now = que.front(); que.pop();
        node * p = nullptr;
        for(int i=0; i<MAXC; ++i)
        {
            if(now->nxt[i] == nullptr) continue;
            if(now == root) now->nxt[i]->fail = root;//root所有子节点fail指向root
            else
            {
                p = now->fail;
                while(p != nullptr)//沿着失败指针往上走
                {
                    if(p->nxt[i] != nullptr)//直到找到一个存在s[i]子节点的节点
                    {
                        now->nxt[i]->fail = p->nxt[i];//失败指针指向该子节点
                        break;
                    }
                    p = p->fail;
                }
                if(p == nullptr) now->nxt[i]->fail = root;//没有找到, fail指向root
            }
            que.push(now->nxt[i]);
        }
    }
}

vector<pair<int, int>> query(const char *s, node *root)
{
    vector<pair<int, int>> ret;
    int len = strlen(s);
    node * p = root;
    for(int i=0; i<len; ++i)
    {
        int index = s[i] - 'a';
        while(p->nxt[index] == nullptr && p!=root) p = p->fail;//如果这个字母没有匹配, 沿着失败指针走,
                                                                //直到匹配或者到root
        if(p->nxt[index] == nullptr) continue;//没有匹配
        p = p->nxt[index];
        node * t = p;
        while(t!=root)//匹配, 沿着这个节点的失败指针, 找到所有以s[i]结尾的节点
        {
            if(t->id != -1) ret.push_back(make_pair(t->id, i));
            t = t->fail;
        }
    }
    return ret;
}

void del(node * root)
{
    for(int i=0; i<MAXC; ++i) if(root->nxt[i] != nullptr) del(root->nxt[i]);
    delete root;
}


int main()
{
    node * root = new node;
    int id = 0;
    while(cin >> keyword && keyword[0]!='#')
        insert(keyword, id++, root);
    build_fail_point(root);
    cout << " s " << endl;
    cin >> s;
    vector<pair<int, int>> v = query(s, root);
    for(auto x : v) cout << x.first << "  " << x.second << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值