【编译原理总结】由正则式构造等价的DFA并将其最小化

前言

编译原理真的是天书,老师课上讲的我是完全不懂的,以下仅仅是个人通过搜集资料和做题得出来的解题方法,可能只能拿来应付做题考试,并非专业理论的东西,我将用尽可能简单易懂的办法来叙述。

方法

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拿进去走,能得到的状态的集合。

II1I0
   

然后我们来看NFA图,代入不同符号(要注意只要包括这个符号,前后可以有任意个ε),找到他们能走到的状态的集合。

首先我们以S开始,经过任意个ε得到的结点就是第一个I,这道题就是{S}(因为我们发现图中S只能给个1才能到A,给其他任何符号都走不下去),故我们在表格中第一行第一列填入{S}

II1I0
{S}  

然后将1拿进去让他去一步步走,能得到状态A(如下图),那么此时集合I1就是{A}

但是别着急,我们继续往后看,A如果读进空字符串ε还能到B,再读一个ε还能到C,而且B读一个1以后还能到B自身

          

那么此时集合就是{A,B,C},我们将其填入第一行的第二列

II1I0
{S}{A,B,C} 

I0同理,我们发现S代入0让他走,没办法到任何节点,故我们填入空集∅

II1I0
{S}{A,B,C}

 

第一行至此完成。

接着我们看表格中还有没有没处理过的集合(即表格中还存在没有在第一列中的集合)

我们发现{A,B,C}还不存在于第一列中,我们将其填入

II1I0
{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},将其填入第二行第二列

II1I0
{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},将其填入第二行第三列

II1I0
{S}{A,B,C}
{A,B,C}{B,C,D}{B,C}

重复上面的工作,我们发现集合{B,C,D}和集合{B,C}在第一列中还不存在,故拿过去,再算!

II1I0
{S}{A,B,C}
{A,B,C}{B,C,D}{B,C}
{B,C,D}  
{B,C}  

 

中间的过程都是一样的,就不再重复了,最后我们得到的表格是这样的:

II1I0
{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,可以是随意的。

II1I0
A    {S}{A,B,C}
  {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}

然后,在后面几列中的状态集按照第一列的编号,也写出来,方便后面我们画箭头。

II1I0
A    {S}{A,B,C}   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}

\pi _{0}=\left ( \left \{ A,B,C,D,E \right \}, \left \{ Z \right \}\right )

接下来分别代入符号(本例中是0和1),找出从各个集合中的各个状态从这个符号出发到的状态的集合,再比较是否是上一个π中的子集。

一个化简:观察一下DFA图,我们发现在集合{A,B,C,D,E}中,B,C,D,E代入0和1都是允许的,但A只能代入1,无法代入0,因此我们首先就可以把A单独提出来。

因此变成:

\pi _{0}=\left ( \left \{ A \right \},\left \{ B,C,D,E \right \}, \left \{ Z \right \}\right )

例如本题中,我们将{B,C,D,E}中各个状态先代入0得到的状态集合如下:

\left \{ B,C,D,E \right \}_{0}=\left \{ D,E \right \}

针对上述结果集合的说明:

B代入0得到D

C代入0得到E

D代入0得到D

E代入0得到D

故结果集合为{D,E}

我们发现

\left \{ D,E \right \}\subseteq \pi _{0}

针对上述式子的说明:

因为π0中包含集合{B,C,D,E},而{D,E}是{B,C,D,E}的一个子集,故得到此结果。

接下来我们将{B,C,D,E}中各个状态先代入1得到的状态集合如下:

\left \{ B,C,D,E \right \}_{1}=\left \{ C,Z \right \}

我们发现

\left \{ C,Z \right \}\nsubseteq \pi _{0}

因此我们需要将集合{B,C,D,E}进一步拆分。

通过上面的计算方法,我们知道了:如果π中的一个集合代入各个状态,只要出现得到的结果集合不是π的子集的情况,就需要进一步拆分。

我们可以简单观察得到{B,C,D}代入0和1以后得到集合都是π0的子集,但E代入1后突然就多出个Z,因此将{B,C,D,E}分为{B,C,D}和{E},得到

\pi _{1}=\left ( \left \{ A \right \},\left \{ B,C,D \right \},\left \{ E \right \}, \left \{ Z \right \}\right )

重复刚才的操作,有

\left \{ B,C,D \right \}_{0}=\left \{ D,E \right \}\nsubseteq \pi _{1}

因此再将{B,C,D}拆分,如何拆分的方法还是跟上面一样的:

\pi _{2}=\left ( \left \{ A \right \},\left \{ B,D \right \},\left \{ C \right \},\left \{ E \right \}, \left \{ Z \right \}\right )

再一次检查,这次我们发现

\left \{ B,D \right \}_{0}=\left \{ D \right \}\subseteq \pi _{2}

\left \{ B,D \right \}_{1}=\left \{ C \right \}\subseteq \pi _{2}

终于,我们得到了最小化的集合π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能到他自身。

至此,本题已经做完,方法也应该掌握!

完结散花。

后记

技术和知识储备有限,在编写过程中可能会存在错误,如果您发现了错误请您在下方评论中发出,我会及时更正,谢谢!

  • 54
    点赞
  • 207
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
编译原理学习计算机科学的一门基础课程,主要涉及语言的识别和转化,而正则表达式则是其中一个非常重要的工具。在编译原理中,正则表达式通常用于描述一些模式,比如关键字、标识符等。因此,掌握正则表达式的转换过程对于理解编译原理课程非常重要。 正则表达式的转换过程主要包括以下几个部分:正则表达式转NFA、NFA转DFADFA最小化。其中,NFA(非确定有限状态自动机)和DFA(确定有限状态自动机)都是描述正则表达式的模型。 正则表达式转NFA: 首先,正则表达式中的基本元素是字符、括号和运算符。在转换为NFA的过程中,需要设计出一些状态来描述不同的字符和运算符。 对于字符来说,我们可以为它们设计出一个状态状态的入口边是字符,出口边为空。 对于括号和运算符来说,可以为它们设计出一些连接状态。例如在括号中的字符可以通过连接状态直接连接到后面的状态,或者通过其他运算符先连接到其他的状态再连接到后面的状态。 最后,需要定义一个起始状态和一个终止状态,起始状态与第一个字符状态相连,最后一个字符状态与终止状态相连。这样,我们就得到了一张NFA图。 NFA转DFA: 将一个NFA图转换成DFA图的主要目的是为了简化图结构,以便后续对文本进行识别。 首先,需要定义DFA状态集合,每个集合都对应一个状态。因为DFA是完全确定的有限状态自动机,所以在DFA中只能有一个状态。 然后,需要将NFA图中的每个状态都映射为DFA图中的一个状态,以便对文本进行识别。当NFA图中有多个状态对应于DFA图中的同一状态时,需要将它们合并,并将它们的出口边合并成一个出口边。 DFA最小化: 最后,对DFA进行最小化处理,以便减少状态数,提高运行效率。在最小化处理时需要考虑不同状态之间的等价关系。 可以采用遍历算法,将DFA中的状态按照等价关系划分为若干个等价类,然后构造一个等价类访问表,每个表项对应一个状态集。 最小化后的DFA图是可以识别文本的,可以用于在编译器中进行文本匹配和词法分析等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值