1、算法流程图

(1)    void Init()

此函数是初始化函数,用来给fail数组和goto数组初始化值。

(2)    void GotoFunction(string x)

这个函数的作用是生成有限自动机状态转移图。

(3) void FailFunction(int target,int k)

这是fail函数,核心内容是求出每个状态的fail值。

(4) void UpdateOutput()

这是update输出函数。其作用是更新每个状态的输出值。

5void Check(string x)

这个是check函数,其作用是判断改状态下output函数是否有输出,如果有输出就输出相应状态下的字符串。并且决定该状态接受输入之后的去向,如果fail,则调用该状态的fail 函数来决定去向。

6int main()

主函数,整个过程的入口。



2、自动机所定义的数据结构及其功能

(1)             int Goto[M][26];

goto数组是状态机状态的载体,内部存储着本次实验的全部状态。起始状态为0,之后每获得一个有效输入就生成一个新的状态。但是在生成状态之前要进行检验,看是否已经存在本次状态。

(2)             int Fail[M];

fail数组存储的是该状态获得输入后,如果结果为fail之后的转向状态。

(3)             string Output[M];

output数组是一个字符串数组,存储的是以该状态为终结状态的字符串。当然,字符串不唯一,AC算法的核心任务之一就是找到每个状态为终结状态时候的全部输出字符串。

(4)             string Depth[M];

depth数组用来标示该状态在第几层。我们在此次实验中将goto函数创建的状态看作一个树,因此必然需要一个数组来指明树中的节点所在的层数。



3、转向函数、失效函数、输出函数的构建过程

(1)             转向函数

我们首先来看其伪代码:

结合伪代码和刚才的函数流程图,我们可以看出转向函数首先对数组进行初始化。其次,来看while循环。如果g(state,aj)!=fail,那么就将g(state,aj)赋值给state,其目的是如果已经存在的状态就不必再次创建,只需要不断地向前更新状态即可。可是如果g(state,aj)=fail,那么我们就要创建新的状态,即newstate+1,并将g(state,aj)指向此状态,再更新状态。在函数最后,构建部分output函数。

(2)             失效函数

我们来看fail函数的伪代码:

Fail函数采用队列作为核心数据结构。首先将0状态后的有效状态加入队列。如果队列不空,就会一直执行while循环中的代码。首先将队首取出,将队首能够到达的有效状态依次加入队列。求出已取出的队首的fail值并作为state。接下来判断g(state,a)是否为fail。如果不是fail,那么该值就会作为新入队列的队首的fail值。依次类推,用队列以层序的方式将状态图中每一个状态的fail值都求出来。求出了改状态的fail值之后,应该将此状态的输出并上fail状态的输出。这是很关键的一步,用以更新output数组输出值。

(3)             输出函数

同样我们来看看output函数的伪代码

Output本质就是在模拟自动机执行的过程。首先进入while循环,如果g(state,a)为fail,那么就调用改状态的fail函数,并将函数值更新给state。直到跳出while循环,之后状态往前走一步,并判断改状态是否有输出。如果有输出,就先将改状态的输出打印出来,再继续读入下一个输入。



4、  源代码

#include<iostream>

#include<string.h>

#define M 20//State_Number

using namespace std;

int Goto[M][26];

int Top;

int Fail[M];

string Output[M];

string Depth[M];

void Init()

{

Top=0;

for(int i=0;i<M;i++)

{

Fail[i]=0;

for(int j=0;j<26;j++)

{

Goto[i][j]=0;

}

Depth[i]=Output[i]="";

}

Depth[0]+='0';

}

void GotoFunction(string x)

{

int len=x.length();

int next=0;

for(int i=0;i<len;i++)

{

int index=x[i]-97;/*a->0*/

if(Goto[next][index]==0)

{

Goto[next][index]=++Top;

next=Top;

}

else

{

next=Goto[next][index];

}

char num=next+48;/*0->'0'*/

if(Depth[i+1].find(num)==Depth[i+1].npos)

{

/*

这段代码很巧妙,他本质上是用一个数组来模拟树

其作用是让i+1层囊括这一层的所有状态

*/

Depth[i+1]+=num;//每一层都有哪些状态

}

}

Output[next]+=x;//构建output数组,在next位置输出x字符串

}

void FailFunction(int target,int k)

{

for(int i=0;i<Depth[k].length();i++)

{

int num=Depth[k][i]-48;

for(int j=0;j<26;j++)

{

if(Goto[num][j]==target)

{

/*

这一段是核心代码

首先找到state

然后根据算法构建target的fail值

*/

int state=Fail[num];

Fail[target]=Goto[state][j];

return;

}

}

}

}

void UpdateOutput()

{

int k=2,num;

Fail[0]=0;

for(int i=0;i<Depth[1].length();i++)

{

num=Depth[1][i]-48;

Fail[num]=0;//当然啦,我们规定层数为一的状态fail函数值都为0

}

while(Depth[k]!="")

{

for(int i=0;i<Depth[k].length();i++)

{

num=Depth[k][i]-48;

FailFunction(num,k-1);

/*

这一段是核心代码

就好像广度优先遍历

对于每一层的每一个状态

构建其fail函数值

*/

if(Output[Fail[num]]!="")

{

Output[num]+=" ";

Output[num]+=Output[Fail[num]];

/*

当然这也是核心代码

重构output内部值

*/

}

}

k++;

}

for(int i=0;i<=Top;i++)

{

cout<<'\n'<<i<<'\t'<<Output[i];

}

}

void Check(string x)

{

int state=0,index,i=0;

while(i<x.length())

{

index=x[i]-97;

if(Goto[state][index]!=0||state==0)

{

/*

0状态无论输入什么都不报错

*/

state=Goto[state][index];

if(Output[state]!="")

{

cout<<i+1<<'\t'<<Output[state]<<'\n';

}

i++;

}

else

{

state=Fail[state];

}

}

}

int main()

{

Init();

int i=1;

cout<<"welcome the AC world!"<<endl;

cout<<"please input the "<<i <<" patterns: ";

string x;

cin>>x;

while(x!="exit")

{

i++;

cout<<"please input the "<<i <<" patterns: ";

GotoFunction(x);

cin>>x;

}

UpdateOutput();

cout<<"\n\n";

cin>>x;

Check(x);

}

AC算法学习笔记的更多相关文章

  1. AC自动机学习笔记-2(Trie图&&last优化)

    我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...

  2. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  3. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  6. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  7. AC自动机板子题/AC自动机学习笔记!

    想知道484每个萌新oier在最初知道AC自动机的时候都会理解为自动AC稽什么的,,,反正我记得我当初刚知道这个东西的时候,我以为是什么神仙东西,,,(好趴虽然确实是个对菜菜灵巧比较难理解的神仙知识点 ...

  8. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

  9. R语言实现关联规则与推荐算法(学习笔记)

    R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...

随机推荐

  1. 用C表达面向对象语言的机制——C#版

    PS:本文PDF版在这里(格式更好看一些).最新的源代码请在本页面文末下载,PDF中的链接不是最新的. 用C表达面向对象语言的机制——C#版 我一直认为,面向对象语言是对面向过程语言的封装.如果是这样 ...

  2. xib文件的加载方法

    xib文件的加载方法 以UITableViewCell的cell为例 很多时候因为系统的cell无法满足我们的日常需求,我们都会自定义cell 因为cell的界面比较固定,所以通常都会选择用xib来描 ...

  3. 你所不知道的setInterval

    在你所不知道的setTimeout记载了下setTimeout相关,此篇则整理了下setInterval:作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这set ...

  4. APP测试点总结(功能,交互,死机崩溃状态分析,容易出错的检查点)

    APP测试点总结(功能,交互,死机崩溃状态分析,容易出错的检查点) 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近涉足APP端测试,常见检查点总结如下:   一.业务方面: 1.  注册( ...

  5. 阿里云accessKey如何创建?~ 2015.08.25

    选择导航条上面的ACCESSKeys(工单服务左边,我一开始也没注意到) 创建一下,然后同意 验证一下 收工

  6. .NET Core的文件系统[2]:FileProvider是个什么东西?

    在<读取并监控文件的变化>中,我们通过三个简单的实例演示从编程的角度对文件系统做了初步的体验,接下来我们继续从设计的角度来继续认识它.这个抽象的文件系统以目录的形式来组织文件,我们可以利用 ...

  7. BIRCH聚类算法原理

    在K-Means聚类算法原理中,我们讲到了K-Means和Mini Batch K-Means的聚类原理.这里我们再来看看另外一种常见的聚类算法BIRCH.BIRCH算法比较适合于数据量大,类别数K也 ...

  8. JS处理事件小技巧

    今天,就分享一下我自己总结的一些JS的小技巧: ①防止鼠标选中事件 <div class="mask" onselectstart="return false&qu ...

  9. Federated Identity Pattern 联合身份模式

    Delegate authentication to an external identity provider. This pattern can simplify development, min ...

  10. External Configuration Store Pattern 外部配置存储模式

    Move configuration information out of the application deployment package to a centralized location. ...