AC自动机

我们知道KMP是单模式匹配,求一个串在母串中是否出现过。那么AC自动机就是求多模式匹配的算法,判断n个串是否在母串中出现过。 AC自动机要用到字典树和失败指针两个很关键的东西,下面来具体说一下要怎么构造。 字典树的构造应该是比较容易,一颗以root为根的树,每个节点下面有26个节点,分别代表了a-z的字母;同时还有根据题目需要的一些标志,如该节点是否是单词的结束节点的sum,记录节点到根的长度的length以及访问标志flag。 ![1 建立字典树的过程 struct node{ node *next\[26\]; node *fail;//失败指针 int length;//到根节点的距离 int flag;//访问次数 }; void insert(char *s) { node *p=root; int len=strlen(s); for(int i=0;i<len;i++) { int x=s\[i\]-'a'; if(p->next\[x\]==NULL) { newnode=(struct node*)malloc(sizeof(struct node)); for(int i=0;i<26;i++) newnode->next\[i\]=0; newnode->fail=0;newnode->length=p->length+1; p->next\[x\]=newnode; } p=p->next\[x\]; } } 2 构建失败指针 什么是失败指针?失败指针也就是匹配过程中无法匹配时,跳转到失败指针处看是否能够匹配下去。]![借鉴了一下同学的一个图片,可以很清楚的看到失败指针的用处](https://img-blog.csdn.net/20170821153425525?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzIyMjU3Nzk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 构建bfs的过程可以用队列的思想来做。 每次寻找父亲节点的指针处,判断此节点是否有该字母 void build_fail_point()//构建失败指针 { int head=0,tail=1; node *temp,*p; q[head]=root; while(head<tail) { temp=q[head++]; for(int i=0;i<=25;i++) { if(temp->next[i]) { if(temp==root) { temp->next[i]->fail=root; } else { p=temp->fail; while(p) { if(p->next[i]) { temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root; } q[tail++]=temp->next[i]; } } } } 3 检索的过程 具体的检索过程要根据题目来进行 比如说这里我们以hdu6138为例,每次检索标记处访问过的节点。 void search(char *s,int f)//标记被访问过的节点 { node *p=root; int len=strlen(s); for(int i=0;i<len;i++) { int x=s[i]-'a'; while(p->next[x]==NULL&&p!=root) p=p->fail; if(p->next[x]!=NULL) p=p->next[x]; node *temp=p; while(temp!=root) { temp->flag=f; temp=temp->fail; } } }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值