编译原理实验报告(二) E01214055 鲁庆河1.实验名称:不确定有穷状态自动机的确定化2.实验目的:a)输入:非确定有穷状态自动机NFAb)输出:确定化的有穷状态自动机DFA3.实验原理:a)NFA确定化为DFA同一个字符串α可以由多条通路产生,而在实际应用中,作为描述控制过程的自动机,通常都是确定有限自动机DFA,因此这就需要将不确定有限自动机转换成等价的确定有限自动机,这个过程称为不确定有限自动机的确定化,即NFA确定化为DFA。
b)NFA的确定化算法 ----- 子集法:●若NFA的全部初态为S1,S2,…,S n,则令DFA的初态为:S=[S1,S2,…,S n],其中方括号用来表示若干个状态构成的某一状态。
●设DFA的状态集K中有一状态为[S i,S i+1,…,S j],若对某符号a∈∑,在NFA中有F({ S i,S i+1,…,S j},a)={ S i’,S i+1’,…,S k’ },则令F({ S i,S i+1,…,S j },a)={ S i’,S i+1’,…,S k’ }为DFA的一个转换函数。
若[ S i’,S i+1’,…,S k‘ ]不在K中,则将其作为新的状态加入到K中。
●重复第2步,直到K中不再有新的状态加入为止。
●上面得到的所有状态构成DFA的状态集K,转换函数构成DFA的F,DFA的字母表仍然是NFA的字母表∑。
●DFA中凡是含有NFA终态的状态都是DFA的终态。
c)closure(I)函数,move(I,a)函数的假设I是NFA M状态集K的一个子集(即I∈K),则定义ε-closure(I)为:1.若Q∈I,则Q∈ε-closure(I);2.若Q∈I,则从Q出发经过任意条ε弧而能到达的任何状态Q’,则Q’∈closure(I)。
3.状态集ε-closure(I)称为状态I的ε闭包。
假设NFA M=( K,∑,F,S,Z ),若I∈K,a∈∑,则定义I a=closure(J),其中J是所有从closure(I)出发,经过一条a弧而到达的状态集。
NFA确定化的实质是以原有状态集上的子集作为DFA上的一个状态,将原状态间的转换为该子集间的转换,从而把不确定有限自动机确定化。
经过确定化后,状态数可能增加,而且可能出现一些等价状态,这时就需要简化。
4.实验思路:(数据结构及变量设计等)5.实验小结:在写此次试验之初,数据结构设计是这样的,K,E,S,Z都用一位字符数组存储,F用下面的链表存储,但是最终在写move函数时查找J集合麻烦,加之数据结构算法的实现基本功不够,在同学的指点下就从新定义了数据结构。
在新的数据结构中,使用邻接表来存储转换函数的,虽然数据结构部分对于顺序表链表邻接表的操作很陌生,但通过此次的实验让我对于数据结构中邻接表的使用有了很好的复习和回顾,也学会了邻接表中指针的使用和插入删除操作……此次实验过程中,代码虽然全部都是本人自己编写,但很多不是我自己的思想,是从同学那剽窃来理解消化的,在别人和我讲述了代码之后,我自己独立的去写时,细节的地方仍然是漏洞百出,到处出错。
我的代码能力太差,也常常因为这而自卑,但也不知如何去提升,虽然课本上的确定化会写,算法也能够理解和掌握,但是实现起来就是无从下手,所以动手能力差的同时,书本知识也得不到强化。
我会借编译原理实验的机会慢慢的熟悉代码,自己去想通算法,自己去实现算法。
我很感激姚老师的严厉要求,我相信我们院的老师都要像您和王爱平老师这样的就好了!6.附件:(程序和运行结果截图)a)程序:#include <stdlib.h>#include <malloc.h>#include <stdio.h>#include <conio.h>#define N 20 //用于控制数组的最大长度//用邻接表存储NFA和DFA的状态字母后继typedef struct adjvex{//定义邻接表的邻接点域的数据表示char nextstate;//头结点状态的后继状态char arc;//弧struct adjvex *next;//指向该头结点状态的下一个后继状态的指针}adjvex;typedef struct headvex{//定义邻接表的头部的数据表示char state;//状态adjvex *firstarc;//指向第一个后继状态的指针}headvex;//定义两个邻接表的头部,为全局数组headvex NFA[N];//用邻接表存储的NFAheadvex DFA[N];//用邻接表存储的DFAchar Alp[N];//存储需要输入的行为集,即字母表void main(){void designby();//函数声明void closure(char s,char set[N]);//求e_closure闭包函数void Special(char DFA_start[N],char new_state[N][N]);//确定化函数designby();int i,j;char NFA_start[N];//存放NFA的初态char DFA_start[N];//存放DFA的初态char NFA_final[N];//存放NFA的终态char DFA_final[N];//存放DFA的终态char new_state[N][N];//存放DFA的I的二维数组每一行为一个原NFA的一个新的状态集,e-closure(move(I,a)) for(i=0; i<N; i++){NFA[i].state='#';NFA[i].firstarc=NULL;DFA[i].state='#';DFA[i].firstarc=NULL;Alp[i]='#';NFA_start[i]='#';DFA_start[i]='#';NFA_final[i]='#';DFA_final[i]='#';for(j=0; j<N; j++)new_state[i][j]='#';}int m,n;printf("请输入NFA: 状态的个数:[ ]\b\b\b");scanf("%d",&n);fflush(stdin);printf(" 状态转换个数:[ ]\b\b\b");scanf("%d",&m);fflush(stdin);printf("请输入各状态:(状态,0/1/2),终态输2,非初终态输1,初态输0.\n");//创建邻接表int f;for(i=0; i<n; i++)//n个状态的输入,依次存储到已开辟空间的邻接表头结点中,并根据状态分类装入NFA的初态终态数组中.{printf("状态%d:",i+1);scanf("%c,%d",&NFA[i].state,&f);fflush(stdin);if(f==0)//输入状态若为初态,依次存入到NFA_start[N]数组中{for(j=0; j<N && NFA_start[j]!='#';j++);NFA_start[j]=NFA[i].state;}if(f==2)//输入状态若为终态,依次存入到NFA_final[N]数组中{for(j=0; j<N && NFA_final[j]!='#';j++);NFA_final[j]=NFA[i].state;}}printf("输入完毕!\n\n");printf("请输入状态转换函数:(状态1,状态2,输入字符)\n");adjvex *p;//定义一个指向adjvex的指针pchar from,to,arc;int k;for(i=0; i<m; i++)//m个转换函数的输入,开辟空间并依次存储至相应头结点状态的邻接表中.{printf("状态转换%d:",i+1);scanf("%c,%c,%c",&from,&to,&arc);fflush(stdin);p=(adjvex *)malloc(sizeof(adjvex));p->nextstate=to;p->arc=arc;for(k=0; NFA[k].state!=from; k++);//结束时k的值即为匹配状态所在的头结点p->next=NFA[k].firstarc;//前插法插入结点到头结点后NFA[k].firstarc=p;//前插法插入结点到头结点后if(arc!='$')//输入字符不为空,保存到Alps[N]字母表中{for(j=0; j<N && Alp[j]!='#';j++)if(arc==Alp[j])break;//存在则跳出,结束不保存//上循环结束的两个可能: 1、该输入字符已经存在于字母表中不存跳出,则下面的if也不会成立;//2、从0开始到#结束都没找不到一样的字母,结束for,记下了j.if(Alp[j]=='#') Alp[j]=arc;}}printf("输入完毕!\n\n");//求所有NFA_start[N]中所有初态的closure形成总的初态DFA_start[N]//char start[N][N];//for(i=0; i<N; i++)// for(j=0; j<N; j++)// start[i][j]='#';//for(i=0; NFA_start[i]!='#'; i++)//依次对每个NFA初态求等价状态放在二维数组中// closure(NFA_start[i],DFA_start);/*int k;for(i=0; NFA_start[i]!='#'; i++)//将start二维数组变到一位数组DFA_start[N]中for(j=0; start[i][j]!='#'; j++){k=0;for(k=0;DFA_start[k]!=start[i][j] && DFA_start[k]!='#';k++);if(DFA_start[k]=='#')DFA_start[k]=start[i][j];else continue;}*/k=0;while(NFA[k].state!=NFA_start[0])k++;closure(NFA[k].state,DFA_start);//求初态的e_closure闭包//for(int z=0; z<N; z++)//printf("%4c %4c\n",NFA_start[z],DFA_start[z]);Special(DFA_start,new_state);//有DFA_start[N],即为new_state[0]通过对NFA[N]邻接表依次求// for(z=0; z<N; z++)// {// printf("%s\n",new_state[z]);// }k=0;for(i=0;i<N&&new_state[i][0]!='#';i++)//寻找DFA的终态{for(j=0;j<N&&new_state[i][j]!='#';j++){for(f=0;f<N&&NFA_final[f]!='#';f++)if(new_state[i][j]==NFA_final[f]){DFA_final[k]=i+65;k++;break;}if(new_state[i][j]==NFA_final[f])break;}}//NFA和DFA的输出:k=0;for(i=0;i<N&&new_state[i][0]!='#';i++)//寻找DFA的终态for(j=0;j<N&&new_state[i][j]!='#';j++){for(f=0;f<N&&NFA_final[f]!='#';f++)if(new_state[i][j]==NFA_final[f]){DFA_final[k]=i+65;k++;break;}if(new_state[i][j]==NFA_final[f])break;}printf("确定化后的DFA如下所示:\n");printf(" ");for(i=0;Alp[i]!='#';i++)printf("%3c",Alp[i]);printf(" 初终");printf("\n");for(i=0;DFA[i].state!='#';i++)//以矩阵形式输出DFA{printf("%4c",DFA[i].state);for(j=0;Alp[j]!='#';j++){p=DFA[i].firstarc;while(p){if(p->arc==Alp[j]){printf("%3c",p->nextstate);break;}elsep=p->next;}if(p==NULL)printf(" ");}for(k=0;k<N&&DFA_final[k]!='#';k++)if(DFA[i].state==DFA_final[k])break;if(DFA_final[k]=='#')printf(" 0");elseprintf(" 1");printf("\n");}printf("每个新的状态对应的原状态子集如下:\n");//输出对应的NFA子集for(i=0;i<N&&new_state[i][0]!='#';i++){printf("%3c",i+65);printf(" {");for(j=0;j<N&&new_state[i][j+1]!='#';j++)printf("%c,",new_state[i][j]);printf("%c}",new_state[i][j]);printf("\n");}printf("新的终态如下:\n");for(i=0;i<N&&DFA_final[i]!='#';i++){printf("%3c",DFA_final[i]);}printf("\n");}void closure(char s,char set[N])//找一个状态s经过任意连续个的空弧所到达的等价状态的集合set[N](包括自身即为0条空弧) {int i,j;for(i=0;set[i]!='#';i++)//将自身存储到set[N]中,0条空弧if(set[i]==s)break;if(set[i]=='#')set[i]=s;for(j=0;NFA[j].state!=s;j++);//查找相应状态所在的邻接表的头结点状态位置jadjvex *p;p=NFA[j].firstarc;//指针p指向该头结点状态的第一个后继状态while(p){if(p->arc=='$'){closure(p->nextstate,set);//若为空弧的话,递归进入该后继状态所对应的头结点状态处依次查找其空弧后继,查找结束回到上一层后继状态继续查找p=p->next;}elsep=p->next;//查看该头结点状态的下一个后继状态}return;}void move(char From[N],char arc,char To[N])//找一个状态集From[N]的所有状态的arc后继状态的集合To[N]{int i,j,k,t=0;adjvex *p;j=0;//首先定义j为0for(i=0; i<N && From[i]!='#';i++ )//依次对其中的每一个状态求move,直至结束{for(k=0;NFA[k].state!=From[i];k++);//查找相应状态所在的邻接表的头结点状态位置jp=NFA[k].firstarc;//指针p指向该头结点状态的第一个后继状态while(p)//逐个后继状态往后判断后继结束,每次将弧为arc的状态保存到To[N]中if(p->arc==arc){for(k=0; k<N && To[k]!='#'; k++)if(To[k]==p->nextstate){p=p->next;break;//该状态若已存在To[N]中,跳出循环不保存,移动指针查看下一个后继状态}if(To[k]=='#')//直达结束没有发现已经存入,{To[t++]=p->nextstate;p=p->next;}}else p=p->next;}}void Order(char a[N]){//由小到大对数组中的每个字符排序int i,j;char temp;for(i=0;i<N&&a[i]!='#';i++)for(j=i+1;j<N&&a[j]!='#';j++){if(a[j]<a[i]){temp=a[i];a[i]=a[j];a[j]=temp;}}}void Special(char DFA_start[N],char new_state[N][N]){int i,j;char To1[N],To2[N];char order1[N],order2[N];for(i=0; i<N; i++){To1[i]='#';To2[i]='#';}for(i=0; i<N && DFA_start[i]!='#';i++)new_state[0][i]=DFA_start[i];//将DFA_start[N]复制到new_state[0],作为一个状态int st,k,t;adjvex *p;for(st=0; st<N && new_state[st][0]!='#'; st++ ){DFA[st].state=st+65;for(i=0; Alp[i]!='#'; i++){for(k=0; k<N; k++){To1[k]='#';To2[k]='#';//每次使用TO1,To2都要清除原有数据}move(new_state[st],Alp[i],To1);for(j=0;To1[j]!='#';j++)//循环求状态集的closure闭包(求每一个状态的closure时,都会对上一个状态得到的To2[N]从头找不相同的存进去){closure(To1[j],To2);}for(j=0; j<N&&new_state[j][0]!='#'; j++){//将new_state和closure( move(I,a) )转存到两个新数组中,排序比较是否已经存在此状态集合,以防出错for(k=0; k<N; k++){order1[k]=new_state[j][k];order2[k]=To2[k];}Order(order1);Order(order2);//比较是否相等for(k=0;k<N&&order1[k]!='#'&&order2[k]!='#'; k++)if(order1[k]!=order2[k]) break;if(order1[k]==order2[k]) break;//前面比较一直相等,最后第k个也为#,同时结束,说明相同}if(new_state[j][0]=='#')//不存在与新状态相等的状态,将其存入最后一行new_state[j]{for(t=0;t<N&&To2[t]!='#';t++)new_state[j][t]=To2[t];}p=(adjvex *)malloc(sizeof(adjvex));//为这个状态转换创建一个结点p->nextstate=j+65;p->arc=Alp[i];p->next=DFA[st].firstarc;DFA[st].firstarc=p;}}}void designby(){printf("\n\t\t编译原理实验(二)\n\n");printf("\t实验名称:不确定有穷状态自动机的确定化.\n");printf("\t实验目的:输入:非确定有穷状态自动机NFA\n");printf("\t 输出:确定化的有穷状态自动机DFA\n\n");printf("\t姓名:鲁庆河( E01214055 )\n");printf("\t日期:2015.05.12 -- 2015.05.15\n");getch();printf("\n");}b)截图:。