定义这里状态 的概念:状态代表当前已经匹配的字符个数。状态转移代表,在当前状态下,输入一个字符让当前状态发生变化。
关于自动机原理,请参考其他编译原理书籍
自动机M是一个元组(Q,q, A, ∑,δ)
Q是状态的有限集合
q∈Q是一个初始状态
A属于Q是 特殊的接受状态集合
∑是有限输入字母表
有限自动机开始于状态q,每次读入输入字符串的一个字符。如果有限自动机在状态q的时候读入了字符a,则它从状态q转变为δ(q,a)。每当其当前状态q输入A时,就说自动机M接受了迄今为止所读入的字符串。没有接受的输入称为被拒绝的输入。
有限自动机M引入一个函数ф,称为终态函数,它是从∑*到Q的函数,满足ф(w)是M在扫描字符串w后终止时的状态。因此,当且仅当ф(w)∈A时,M接受字符串w。我们可以用转移函数递归定义ф:
有限自动机M引入一个函数ф,称为终态函数,它是从∑*到Q的函数,满足ф(w)是M在扫描字符串w后终止时的状态。因此,当且仅当ф(w)∈A时,M接受字符串w。我们可以用转移函数递归定义ф:
ф(ε)=q;
ф(wa)=δ(ф(w),a)
考虑以下两种情况。第一种情况是,a=P[q+1],使得字符a继续匹配模式。在这种情况下,由于δ(q,a)=q+1,转移沿着自动机的主线继续进行。第二张情况a≠P[q=1],使得字符a不能继续匹配模式。这时我们必须 找到一个更小的 子串,它是P的前缀同时也是Ti的 后缀。因为当创建字符串匹配自动机时,预处理匹配模式和自己, 转移函数很快得出最长的这样的较小P前缀
#include<iostream>
#include<vector>
#include<map>
#include<string.h>
using namespace std;
bool Matching_Prefix(const char *P,int k,int q,char a){
if(k==0)
return true;
if(k==1){
return P[0]==a;
}
return P[k-1]==a&& (strncmp(P,P+q-k+1,k-1)==0);
}
vector<map<char,int>> Compute_Transition_Function(const char *P,const char*input_character ){
int m=strlen(P);
int j=0,k;
cout<<m<<endl;
vector<map<char,int> >transition_map(m+1);
for(int i=0;i<m;i++){
j=0;
cout<<"p:"<<i<<endl; //状态i
while(input_character[j]!='\0'){
k= min(m+1,i+2);
do{
k=k-1;
}while(!Matching_Prefix(P,k,i,input_character[j]));
transition_map[i][input_character[j]]=k;
cout<<"状态p:"<<i<<", 输入字符"<<input_character[j]<<", k:"<<k<<endl; //输出状态转移函数
j++;
}
}
return transition_map;
}
void Finite_Automaton_Matcher(char *T,char*P,vector<map<char,int>>transition_map){
int n=strlen(T);
int m=strlen(P);
int q=0 ; //初始状态为0
for(int i=0;i<n;i++){
q = transition_map[q][T[i]];
if(q==m)
cout<<"Pattern occurs whit shift"<<i-m<<endl;
}
}
int main(){
const char *input_character="abcdefghijklmnopqrstuvwxyz"; //有限输入字母表
char T[]="abdfdfsdklfdjgkjgdkjerdfgfdg";
char P[11]= "dklfdjgkj";
vector<map<char,int>>transition_map=Compute_Transition_Function(P,input_character);
Finite_Automaton_Matcher(T,P,transition_map);
return 0;
}
从Finite_Automaton_Matcher简单的循环结构可以看出,对于一个长度为n的文本字符串,它的匹配时间为Θ(n),的,但是没有加上计算转移函数的预处理时间。
预处理Computer_Transition_Function的运行时间为Θ(m^3 |∑|)。当然预处理可以改进为Θ(m|∑|),所以最后的时间为Θ(n)匹配时间加上Θ(m)的预处理时间。