NFA转换为DFA及DFA的化简.docx

上传人:b****6 文档编号:4765901 上传时间:2022-12-08 格式:DOCX 页数:38 大小:335.82KB
下载 相关 举报
NFA转换为DFA及DFA的化简.docx_第1页
第1页 / 共38页
NFA转换为DFA及DFA的化简.docx_第2页
第2页 / 共38页
NFA转换为DFA及DFA的化简.docx_第3页
第3页 / 共38页
NFA转换为DFA及DFA的化简.docx_第4页
第4页 / 共38页
NFA转换为DFA及DFA的化简.docx_第5页
第5页 / 共38页
点击查看更多>>
下载资源
资源描述

NFA转换为DFA及DFA的化简.docx

《NFA转换为DFA及DFA的化简.docx》由会员分享,可在线阅读,更多相关《NFA转换为DFA及DFA的化简.docx(38页珍藏版)》请在冰豆网上搜索。

NFA转换为DFA及DFA的化简.docx

NFA转换为DFA及DFA的化简

实验三

(一)NFADFA(2小时)

实验目的:

学会编程实现子集构造法

实验任务:

存储NFA与DFA,编程实现子集构造法将NFA转换成DFA

实验内容:

(1)确定NFA与DFA的存储格式,为3个以上测试NFA准备好存储文件。

NFA的存储格式:

3//转换边数

0//开始状态

3-1//结束状态集,以-1为结束标志

01a//状态转换

02a//如状态0在a输入下转换为状态2

23b//其中用#表示空转换

如测试用例:

(a)以a开头和结尾的小字字母串;a(a|b|…|z)*a|a

(b)不包含三个连续的b的,由字母a与b组成的字符串;(e|b|bb)(a|ab|abb)*

(c)(aa|b)*(a|bb)*

(2)用C或JAVA语言编写将NFA转换成DFA的子集构造法的程序。

子集构造法原理:

子集构造法主要代码:

子集构造函数:

voidchild_method()

{

intm,n;

for(m=0;m<100;m++)

for(n=0;n<100;n++)

Dtran[m][n]='#';

for(m=0;m<100;m++)

DFA[m].flag=-1;

StateS0,U;

S0.flag=0;

S0.count=1;

S0.H[0]=first;

StateT;

T=closure(S0);

T.mark=0;

T.flag=0;

DFA[numof_Dtran++]=T;

memset(useof_DFA,0,sizeof(useof_DFA));

//检查DFA中是否存在未被标记的状态

intj=check_inDFA();

intk;

while(j!

=-1)

{

useof_DFA[j]=1;

for(k=0;k

{

U=closure(move(DFA[j],alpha[k]));//求闭包

//ifU不在DFA中

if(!

check_whetherin_DFA(U))//判断是否在DFA中

{

U.mark=numof_Dtran;

DFA[numof_Dtran++]=U;

}

Dtran[DFA[j].mark][U.mark]=alpha[k];

}

j=check_inDFA();//检查DFA中是否存在未被标记的状态,有返回标号,否则返回-1

}

}

闭包函数:

Stateclosure(StateT)//求闭包

{

stackSTACK;

Statetemp;

inti,j,k;

for(i=0;i

{

STACK.push(T.H[i]);

temp.H[i]=T.H[i];

}

temp.count=T.count;

/*temp.flag=0;*/

temp.mark=T.mark;

while(!

STACK.empty())

{

intt=STACK.top();

STACK.pop();

//搜索状态t通过一个或多个空字符到达的状态

intsearch_result[100];

intnum;

arriveBynone(t,search_result,num);

for(j=0;j

{

if(!

check(search_result[j],temp))

{

temp.H[temp.count++]=search_result[j];

STACK.push(search_result[j]);

}

}

}

for(k=0;k

{

if(f[temp.H[k]]==1)

{

temp.flag=1;

break;

}

if(f[temp.H[k]]==0)

{

temp.flag=0;

break;

}

}

sort(temp.H,temp.H+temp.count);

for(i=0;i

{

if(temp.count!

=DFA[i].count)

continue;

sort(DFA[i].H,DFA[i].H+DFA[i].count);

for(j=0;j

{

if(DFA[i].H[j]!

=temp.H[j])

break;

}

if(j>=DFA[i].count)

temp.mark=DFA[i].mark;

}

returntemp;

}

检查未标记状态函数:

intcheck_inDFA()//检查DFA中是否存在未被标记的状态,有则返回标号,否则返回-1

{

inti;

for(i=0;i

{

if(!

useof_DFA[i])

returni;

}

return-1;

}

检查一个状态是否在DFA中的函数:

boolcheck_whetherin_DFA(StateT)

{

inti,j;

sort(T.H,T.H+T.count);

for(i=0;i

{

if(T.count!

=DFA[i].count)

continue;

sort(DFA[i].H,DFA[i].H+DFA[i].count);

for(j=0;j

{

if(DFA[i].H[j]!

=T.H[j])

break;

}

if(j>=DFA[i].count)

returntrue;

}

if(i>=numof_Dtran)

returnfalse;

else

returntrue;

}

(3)测试。

利用步骤1中所给的测试用例来验证。

a)以a开头和结尾的小字字母串;a(a|b|…|z)*a|a

运行结果及分析:

结果分析:

首先将读入的NFA信息输出:

然后将转换后的DFA输出,其中2号状态表示转换后的∅状态,即无效状态。

状态解释:

0:

1表示用0状态表示NFA中的1状态

1:

23表示用1状态表示{2,3}状态集合。

2:

表示用2状态表示∅状态,即无效状态。

3:

2表示用3状态表示NFA中的状态2。

最后,判断字符串是否能由此DFA得到:

显然,从以上三个例子可以看出,以a开头且以a结尾的字符串可以由该DFA得到而以b开头或结尾的字符串则无法由该DFA得到。

所以得到的DFA正确。

b)不包含三个连续的b的,由字母a与b组成的字符串;(e|b|bb)(a|ab|abb)*

同样可以得到结果及字符串的判断:

显然,得到的DFA可以接受连续最多2个b,到3个就不能接受,与NFA一样,正确。

c)(c)(aa|b)*(a|bb)*

显然,验证结果均正确。

 

实验三

(二)DFA化简(2小时)

实验目的:

学会编程实现等价划分法化简DFA。

实验任务:

先完善DFA,再化简DFA。

实验内容:

(1)准备3个以上测试DFA文件。

测试文件格式即DFA存储格式说明:

2//字符个数

ab//字符

3//非终结状态个数

1//终止状态个数

012//非终止状态

3//终止状态

12//状态转换表

02//如第二行表示状态1在a输入下转换成状态0,在b输入下转换成状态2

03

32

测试文件1:

测试文件2:

测试文件3:

(2)用C或JAVA语言编写用等价划分法化简DFA的程序。

DFA最小化原理:

●确定型有穷自动机(DFA):

有有穷状态集合和输入符号集合,转移函数,初始状态,以及一个终结状态集合。

表示为 

DFA的状态图:

用箭头来表示状态间的转换,用圆圈+文字表示状态,用一个同心圆表示终结状态,用start表示开始状态。

状态表:

可以想象。

●DFA状态最小化:

最小有限自动机,是指满足下述条件的确定有限自动机:

⑴没有无用状态(无用状态已删除);⑵没有等价状态(等价状态已合并)。

Ⅰ.删除无用状态算法

无用状态是指自动机从开始态出发,对任何符号串都不能到达的状态。

判别算法:

构造有用状态集Qus

⑴设q0为开始态,则令q0∈Qus;

⑵若qi∈Qus且有d(qi,a)=qj则令qj∈Qus;

⑶重复执行⑵,直到Qus不再增大为止。

⑷从状态集Q中,删除不在Qus中的所有状态。

Ⅱ.合并等价状态算法

等价状态:

两个状态i,j等价,当且仅当满足下面两个条件:

1必须同是结束态,或同不是结束态;

2对所有字母表上符号,状态i,j必变换到等价状态。

划分不等价状态集

⑴初始,把状态集Q化分成两个不等价子集:

Q1(结束状态集),Q2(非结束状态集);

⑵把每个Qi再划分成不同的子集,条件是:

对同一Qi中两个状态i和j,若对字母表中的某个符号,变换到已划分的不同的状态集中,则i和j应分离:

如d(i,a)∈Qm,d(j,a)∈Qn且m≠n

⑶重复步骤⑵,直到再不能划分为止;

⑷合并最终划分的每个子集中的各状态(合而为一)。

部分函数代码:

判断等价状态:

while(endflag)

{intflag;

for(i=0;i<(temp+1);i++)//对每个等价类集合

for(intj=0;j

{flag=0;

if(sta[j].lastf==i)

{

for(intk=0;k

/若是在同一个等价类,继续测试if(sta[k].lastf==sta[j].lastf&&sta[k].newf==sta[j].newf)/

for(intt=0;t

{ints1,s2;

s1=move[j][t];

s2=move[k][t];

if(sta[s2].lastf!

=sta[s1].lastf)//出现分歧

{sta[k].newf=f+1;

flag=1;

break;

}

}

}

if(flag==1)

f++;

}

for(i=0;i

if(sta[i].lastf==sta[i].newf)

;

else

break;

if(i==n)//若所有的状态等价类编号不再变化,退出while循环

endflag=0;

for(i=0;i

sta[i].lastf=sta[i].newf;

temp=f;

}//循环结束

判断是否存在不可达状态:

for(i=0;i

{ints0=sta[0].newf;

sta[s0].kd=1;

for(intj=0;j

{sta[move[s0][i]].kd=1;

s0=move[s0][i];

}

}

intunreach=0;

for(i=0;i

if(sta[i].kd==1)

;

else//containunreachblestate

{unreach=1;

cout<<"newstate"<

for(intj=0;j

move[i][j]=-1;

}

(3)测试

测试1:

输入文件已在步骤1中进行过说明。

运行结果及分析:

从输入文件和状态转换图可以看出状态0和状态2是等价状态

可以看出程序将0和2号状态合并,可是建立新的状态转移的时候好像有点问题,没有解决。

测试2:

(测试文件格式在步骤1中)

测试3:

(测试文件格式在步骤1中)

经验证,状态分类是正确的,最小化之后的状态转移有点不对。

 

实验心得:

通过本次实验,学会了如何将一个非确定型状态机转换成确定型状态机以及如何将

一个确定型的有穷自动机化简成一个状态最小的有穷自动机。

更加深刻地理解了有穷自动机、等价状态等概念,同时也遇到了很多困难,例如,如何将一个自动机用C++语言来表示,如何将一个图形改成抽象的语言描述等。

总之,对课本的知识有了进一步的理解,收获颇多。

 

附:

两个实验的代码+工程

 

//NFA转为DFA.cpp:

定义控制台应用程序的入口点。

#include"stdafx.h"

#include

#include

#include

#include

#include

#include

#include

usingnamespacestd;

structedge{

intstart,end;

charc;

}E[100],Ekong[100];//E保存所有的边,Ekong保存转换字符为空的边

structState{

intH[100];//状态集合

intcount;//状态集合中的元素个数

intflag;//是否是接受状态

intmark;//状态编号

};

intn;//n:

边数

intnk=0;//空字符转换的边数

intfirst,accept;//开始状态,接受状态

charalpha[100];//输入字母表,#代表空串

intnumof_char=0;//字母表中的字符个数

intuseof_char[256];//该转换字符是否用过

intf[200];//状态属性标志:

0表示始态,1表示接受态,-1表示中间态

StateDFA[100];//DFA状态集

intuseof_DFA[100];//标志构造出来的状态是否已存在

intnumof_Dtran=0;//最后得到的DFA中的状态数

charDtran[100][100];//DFA状态转换表

voidinput()

{

ifstreamfin("input3.txt",ios:

:

in);

inti,s,e;

charch;

fin>>n;

cout<<"此状态转换有"<

fin>>first;

cout<<"开始状态为:

"<

memset(f,-1,sizeof(f));

memset(useof_char,0,sizeof(useof_char));

f[first]=0;

cout<<"接受状态集:

";

//cin>>accept;

fin>>accept;

while(accept!

=-1)

{

f[accept]=1;

cout<

fin>>accept;

}

cout<<"\n\n起点,终点,转换字符('#'表示空字符):

"<

intk=0;

for(i=0;i

{

fin>>s>>e>>ch;

cout<

E[i].start=s;

E[i].end=e;

E[i].c=ch;

if(ch!

='#'&&!

useof_char[ch])

{

alpha[numof_char++]=ch;

useof_char[ch]=1;

}

if(ch=='#')

{

Ekong[nk].start=s;

Ekong[nk].end=e;

Ekong[nk].c=ch;

nk++;

}

}

}

Statemove(StateT,chars)//c!

='#'

{

Statetemp;

temp.count=0;

/*temp.flag=0;*/

temp.mark=T.mark;

inti,j=0,k=0;

for(i=0;i

{

j=0;

while(j

{

if(E[j].start==T.H[i]&&E[j].c==s)

{

temp.H[temp.count++]=E[j].end;

}

j++;

}

}

returntemp;

}

voidarriveBynone(intt,intresult[],int&num)//搜索状态t通过一个或多个空字符到达的状态,结果存在result中

{

intk=0;

intm=0;

num=0;

stackS;

S.push(t);

intj;

while(!

S.empty())

{

j=S.top();

S.pop();

m=0;

while(m

{

if(Ekong[m].start==j)

{

result[num++]=Ekong[m].end;

S.push(Ekong[m].end);

}

m++;

}

}

}

boolcheck(inti,StateT)//判断状态i是否在T中

{

intj;

for(j=0;j

{

if(T.H[j]==i)

returntrue;

}

returnfalse;

}

Stateclosure(StateT)//求闭包

{

stackSTACK;

Statetemp;

inti,j,k;

for(i=0;i

{

STACK.push(T.H[i]);

temp.H[i]=T.H[i];

}

temp.count=T.count;

/*temp.flag=0;*/

temp.mark=T.mark;

while(!

STACK.empty())

{

intt=STACK.top();

STACK.pop();

//搜索状态t通过一个或多个空字符到达的状态

intsearch_result[100];

intnum;

arriveBynone(t,search_result,num);

for(j=0;j

{

if(!

check(search_result[j],temp))

{

temp.H[temp.count++]=search_result[j];

STACK.push(search_result[j]);

}

}

}

for(k=0;k

{

if(f[temp.H[k]]==1)

{

temp.flag=1;

break;

}

if(f[temp.H[k]]==0)

{

temp.flag=0;

break;

}

}

sort(temp.H,temp.H+temp.count);

for(i=0;i

{

if(temp.count!

=DFA[i].count)

continue;

sort(DFA[i].H,DFA[i].H+DFA[i].count);

for(j=0;j

{

if(DFA[i].H[j]!

=temp.H[j])

break;

}

if(j>=DFA[i].count)

temp.mark=DFA[i].mark;

}

returntemp;

}

intcheck_inDFA()//检查DFA中是否存在未被标记的状态,有则返回标号,否则返回-1

{

inti;

for(i=0;i

{

if(!

useof_DFA[i])

returni;

}

return-1;

}

boolcheck_whetherin_DFA(StateT)

{

inti,j;

sort(T.H,T.H+T.count);

for(i=0;i

{

if(T.count!

=DFA[i].count)

continue;

sort(DFA[i].H,DFA[i].H+DFA[i].count);

for(j=0;j

{

if(DFA[i].H[j]!

=T.H[j])

break;

}

if(j>=DFA[i].count)

returntrue;

}

if(i>=numof_Dtran)

returnfalse;

else

returntrue;

}

voidchild_method()

{

intm,n;

for(m=0;m<100;m++)

for(n=0;n<100;n++)

Dtran[m][n]='#';

for(m=0;m<100;m++)

DFA[m].flag=-1;

StateS0,U;

S0.flag=0;

S0.count=1;

S0.H[0]=first;

StateT;

T=closure(S0);

T.mark=0;

T.flag=0;

DFA[numof_Dtran++]=T;

me

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 其它课程

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1