ac自动机
来源:互联网 发布:java api全部包类 编辑:程序博客网 时间:2024/06/09 11:08
预备知识:kmp算法,字典树
debug了好多天,才终于出正确结果了,终于知道逻辑错误的可怕了,越来越理解什么叫做“比编译错误更折磨人的是逻辑错误”。
ps.学前感觉很难,理解了才感觉自动机这个东西真是很奇妙。
具体实现就看注释了。。。。。。
#include<cstdio>#include<string>#include<queue>#include<iostream>using namespace std;struct node{ char c;//该节点所代表的值,其实不加也可以,因为字典树的每一层就是a-z的字典序 int end;//是否为某个单词的结尾 int num;//以该节点,为结尾的单词个数 node *n[26];//字典树指针 node *fail;//fail指针 char *str;//若该节点是单词结尾,要在此处存入单词,输出统计结果时用 node()//初始化节点 { end = 0; num = 0; fail = NULL; for (int i = 0; i < 26; i++) { n[i] = NULL; } }};queue<node*> endnode;//单词结尾的节点组成的队列,用于最后输出统计结果void insert(node *root, char *c)//字典树中插入字符串{ node *op = root;//将要插入的节点的父节点指针 node *p;//新建节点时使用的操做指针 int x;//存储字符在子结点的下标 for (int i = 0; i < strlen(c); i++) { x = c[i] - 'a'; if (op->n[x] == NULL)//若没有该节点,则分配空间新建节点 { p = (node *)malloc(sizeof(node)); //对新节点赋值 p->fail = NULL; p->end = 0; p->c = c[i]; p->num = 0; //子节点指空 for (int op = 0; op < 26; op++) { p->n[op] = NULL; } op->n[x] = p;//将新节点连入字典树 } if (i == strlen(c) - 1)//当处理到字符串最后一位时,将以此位结尾的单词数目加一 { op->n[x]->end++; op->n[x]->str = c; endnode.push(op->n[x]); } op = op->n[x];//为处理下一个做准备 }}void build_fail(node *root)//建立fail指针,利用队列(FIFO),对字典树广度优先搜索{ node *op,*findfail; //op为要建立fail指针的节点的父指针 //findfail永远指向可能是要找的节点的父节点 queue<node*> k; op = root; //k.push(op); //对root下的第一层做特殊处理,fail指向root for (int i = 0; i < 26; i++) { if (op->n[i] != NULL) { op->n[i]->fail = root; k.push(op->n[i]); } } while (!k.empty()) { op = k.front();//先提取元素,再出队列 k.pop(); findfail = op->fail; for (int i = 0; i < 26; i++) { if (op->n[i] != NULL) { k.push(op->n[i]);//新元素入队 if (findfail->n[i] != NULL) { op->n[i]->fail = findfail->n[i];//op.fail.n[i]存在,则直接建立fail指针 } else//fail指针不存在 { //当findfail追到第二层时,该节点的n[i].fail就是root了。 if (findfail->fail = root) op->n[i]->fail = root; else//让findfail一级一级找它的fail指针,当然提前要做判断 findfail = findfail->fail; } } } }}void ac_automachine(node *root,char *c){ node *op=root; for (int i = 0; i < strlen(c); i++)//对文本处理 { int x = c[i] - 'a'; if (op->n[x] != NULL) { if (op->n[x]->end > 0) { op->n[x]->num++;//判断下是否是单词结尾,是,就++ } op = op->n[x]; continue; } else//当不存在时就跳转到fail指针所指向的位置 { while (op != root)//到root就可以截至 { op = op->fail;//沿着fail指针一直延续下去 if (op->n[x] != NULL) { if (op->end > 0) op->num++; op = op->n[x]; if (op->end > 0) op->num++; break; } } } }}void output(){ while (!endnode.empty()) { node *op = endnode.front(); endnode.pop(); printf("%s的个数:%d\n", op->str, op->num); }}int main(){ node a; a.c = '&'; char c[100] = "sayhgbrherbrbrbrhbrh"; //scanf("%s", c); insert(&a, "say"); insert(&a, "brh"); insert(&a, "she"); insert(&a, "her"); insert(&a, "he"); build_fail(&a); ac_automachine(&a, c); output(); return 0;}
阅读全文
0 0
- AC自动机...
- AC自动机
- AC 自动机
- AC自动机
- AC自动机
- ac自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC 自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- 兄弟连学python》》》》文件操作
- 简单的HTTP请求post,get,put,delete,head方法的实现
- 已知四边形的四个点,求一个点是否在四边形之内的解决方法
- 【SpringData】轻松愉快之玩转SpringData( 第2章 使用传统方式访问数据库
- MOOC清华《VC++面向对象与可视化程序设计》第5章:对话框资源例程(模态对话框样例)
- ac自动机
- 聊聊c++中的set
- 谁是凶手
- C:\Users\[本机账户名]\AppData\Roaming\Microsoft\Excel\
- 一个简单的时间显示(当天时/分/秒,隔天年/月/日)
- 第十三周项目1
- [bzoj4986]MiniumCut
- 通俗理解cookie和session
- 搜索