前言
编译原理真的是天书,老师课上讲的我是完全不懂的,以下仅仅是个人通过搜集资料和做题得出来的解题方法,可能只能拿来应付做题考试,并非专业理论的东西,我将用尽可能简单易懂的办法来叙述。
方法
Step1 由正则式构造出NFA
基本规则如下
我们根据要读入的符号来画这个图,比如读入一个a,那么从前一个状态到后一个状态中间就是一个指向箭头上面写个a,特殊的,例如有 | 或 * 号的,就遵守上图的方法来画,最后就能得到NFA的图。
例如
正则表达式 (ab)*(a*|b*)(ba)* 的NFA转换过程如下:
总的来讲这一步就是按顺序读串(注意括号的先后级),直到形成最后的NFA图。
我们再拿一个正则式举例,接下来的步骤将按照这个正则式完成。
例如正则式 1(0|1) *101 可得到NFA图如下:
Step2 根据NFA图得到“状态转换表”(子集构造法)
完成了第一步的图以后,我们根据图来完成状态转换表。
首先看你的NFA图上有几种符号(不包括空字符串ε)。
例如上图中只有0和1两种符号,那么我们接下来要画的表就一共有2+1(总的状态列)=3列
其中第一列我将其成为总的状态列,第二列即第一列中的每个状态将1拿进去走,能得到的状态的集合,第三列同理,即第一列中的每个状态将0拿进去走,能得到的状态的集合。
I | I1 | I0 |
然后我们来看NFA图,代入不同符号(要注意只要包括这个符号,前后可以有任意个ε),找到他们能走到的状态的集合。
首先我们以S开始,经过任意个ε得到的结点就是第一个I,这道题就是{S}(因为我们发现图中S只能给个1才能到A,给其他任何符号都走不下去),故我们在表格中第一行第一列填入{S}
I | I1 | I0 |
{S} |
然后将1拿进去让他去一步步走,能得到状态A(如下图),那么此时集合I1就是{A}
但是别着急,我们继续往后看,A如果读进空字符串ε还能到B,再读一个ε还能到C,而且B读一个1以后还能到B自身
那么此时集合就是{A,B,C},我们将其填入第一行的第二列
I | I1 | I0 |
{S} | {A,B,C} |
I0同理,我们发现S代入0让他走,没办法到任何节点,故我们填入空集∅
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
第一行至此完成。
接着我们看表格中还有没有没处理过的集合(即表格中还存在没有在第一列中的集合)
我们发现{A,B,C}还不存在于第一列中,我们将其填入
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
{A,B,C} |
然后同理,按照上述办法,我们让A,B,C状态分别读入1,
A读入1后,可以到B(读一个ε,再读一个1),可以到C(读一个ε,再读一个1,再读一个ε),可以到D(读一个ε,再读一个1,再读一个ε,再读一个1)
B读入1后,可以到B,可以到C(读一个1,再读一个ε),可以到D(读一个1,再读一个ε,再读一个1)
C读入1后,可以到D
所以可得到的集合是{B,C,D},将其填入第二行第二列
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
{A,B,C} | {B,C,D} |
然后我们再让A,B,C状态分别读入0,
A读入0后,可以到B(读一个ε,再读一个0),可以到C(读一个ε,再读一个0,再读一个ε)
B读入0后,可以到B,可以到C(读一个0,再读一个ε)
C读入0后,到不了任何状态
所以可得到的集合是{B,C},将其填入第二行第三列
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
{A,B,C} | {B,C,D} | {B,C} |
重复上面的工作,我们发现集合{B,C,D}和集合{B,C}在第一列中还不存在,故拿过去,再算!
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
{A,B,C} | {B,C,D} | {B,C} |
{B,C,D} | ||
{B,C} |
中间的过程都是一样的,就不再重复了,最后我们得到的表格是这样的:
I | I1 | I0 |
{S} | {A,B,C} | ∅ |
{A,B,C} | {B,C,D} | {B,C} |
{B,C,D} | {B,C,D} | {B,C,E} |
{B,C} | {B,C,D} | {B,C} |
{B,C,E} | {B,C,D,Z} | {B,C} |
{B,C,D,Z} | {B,C,D} | {B,C,E} |
至此,我们已经完成了表格。
Step3 根据“状态转换表”得到DFA图
我们对上面的表格,第一列中不同的状态集进行状态编号,如下表中红色标识的编号,这就是我们的DFA图中所有的状态,我将末态定为Z,可以是随意的。
I | I1 | I0 |
A {S} | {A,B,C} | ∅ |
B {A,B,C} | {B,C,D} | {B,C} |
C {B,C,D} | {B,C,D} | {B,C,E} |
D {B,C} | {B,C,D} | {B,C} |
E {B,C,E} | {B,C,D,Z} | {B,C} |
Z {B,C,D,Z} | {B,C,D} | {B,C,E} |
然后,在后面几列中的状态集按照第一列的编号,也写出来,方便后面我们画箭头。
I | I1 | I0 |
A {S} | {A,B,C} B | ∅ |
B {A,B,C} | {B,C,D} C | {B,C} D |
C {B,C,D} | {B,C,D} C | {B,C,E} E |
D {B,C} | {B,C,D} C | {B,C} D |
E {B,C,E} | {B,C,D,Z} Z | {B,C} D |
Z {B,C,D,Z} | {B,C,D} C | {B,C,E} E |
全部标完以后,我们找出末态(终态)
很简单,就是包含NFA中末态的状态,这里A,B,C,D,E,Z六种状态中,只有Z:{B,C,D,Z}包含原NFA中的末态Z
接下来我们来画DFA图,先画出所有的状态,定好初态(我这里是A),末态用双圆圈表示
然后看表,例如第一行,我们发现状态A通过1能走到状态B,通过0走不到任何状态,所以我们画一个箭头到B,上面写上1
同理,再看第二行,一直标下去,最后的结果如下:
至此,我们的DFA图就画完了。
Step4 DFA图的最小化
几个概念:
1.多于状态:对于一个状态Si,若从开始状态出发,不可能到达改状态Si,则Si为多余(无用)状态。
2.死状态:对于一个状态Si,对于任意输入符号a,若转到它本身后,不可能从它到达终止状态,则称Si为死状态。
都称为无关状态
3.等价状态:若Si为自动机的一个状态,我们把从Si出发能导出的所有符号串的集合记为L(Si)。
设有两个状态Si和Sj,若有L(Si)=L(Sj),则称Si和Sj是等价状态。
4.可区别状态:自动机中两个状态Si和Sj,如果它们不等价,则称它们可区别。
5.两个状态(Si和Sj)等价的判断条件:
(1)状态Si和Sj必须同时为终止状态或同时为非终止状态。即终止状态和非终止状态是可区别的。
(2)状态Si和Sj对于任意输入符a∈Σ,必须转到等价的状态里,否则Si和Sj是可区别的。
首先要找出初态和末态的集合,很简单,初态为{A,B,C,D,E},末态为{Z}
接下来分别代入符号(本例中是0和1),找出从各个集合中的各个状态从这个符号出发到的状态的集合,再比较是否是上一个π中的子集。
一个化简:观察一下DFA图,我们发现在集合{A,B,C,D,E}中,B,C,D,E代入0和1都是允许的,但A只能代入1,无法代入0,因此我们首先就可以把A单独提出来。
因此变成:
例如本题中,我们将{B,C,D,E}中各个状态先代入0得到的状态集合如下:
针对上述结果集合的说明:
B代入0得到D
C代入0得到E
D代入0得到D
E代入0得到D
故结果集合为{D,E}
我们发现
针对上述式子的说明:
因为π0中包含集合{B,C,D,E},而{D,E}是{B,C,D,E}的一个子集,故得到此结果。
接下来我们将{B,C,D,E}中各个状态先代入1得到的状态集合如下:
我们发现
因此我们需要将集合{B,C,D,E}进一步拆分。
通过上面的计算方法,我们知道了:如果π中的一个集合代入各个状态,只要出现得到的结果集合不是π的子集的情况,就需要进一步拆分。
我们可以简单观察得到{B,C,D}代入0和1以后得到集合都是π0的子集,但E代入1后突然就多出个Z,因此将{B,C,D,E}分为{B,C,D}和{E},得到
重复刚才的操作,有
因此再将{B,C,D}拆分,如何拆分的方法还是跟上面一样的:
再一次检查,这次我们发现
终于,我们得到了最小化的集合π2
这个集合告诉我们,其实B和D状态是等价的,我们可以去掉一个。
例如我们去掉D,那么此时相当于还剩下A,B,C,E,Z五个状态。(其实你也可以重新给状态命名,这里便于理解就不重命名了)
将这五个状态重新画一下DFA图,就是最小化的DFA图了!
这里注意一下,在原来的DFA图中,E走0可以到D,现在我们知道B和D是等价的,故在最小化DFA图中,E走0能到B
同理,原图中D走0可以到他自身,现在由于B和D是等价的,故在最小化DFA图中,B走0能到他自身。
至此,本题已经做完,方法也应该掌握!
完结散花。
后记
技术和知识储备有限,在编写过程中可能会存在错误,如果您发现了错误请您在下方评论中发出,我会及时更正,谢谢!