NFA的确定化和最小化
前言
期末在即,编译原理的考试真让人头疼,不得不利用这短暂的时间把编译原理的诸多大题过一遍。
如果感兴趣可以参观博主其他一些有关编译原理的相关习题详解,相关文章可以在主页查看:
✈️ 传送门
相关概念
- 什么是有穷自动机?
有穷自动机(也称有限自动机)是一种识别装置,能准确识别正规集,即正规文法和 正规式 所表示的集合。
其中可分为:确定的有穷自动机(DFA)和 非确定的有穷自动机(NFA)
- DFA: M ( K , Σ , f , S , Z ) M(K,Σ,f,S,Z) M(K,Σ,f,S,Z)
- K K K:是所有状态的集合(一般状态用大写字母或者阿拉伯数字表示)
- Σ Σ Σ:是所有输入符号的集合(一般输入符号用小写字符表示)
- f f f:是一种单值映射关系(一般表示: ( K i , Σ i ) = K j (K_i,Σ_i)=K_j (Ki,Σi)=Kj,即状态 K i K_i Ki后面输入字符 Σ i Σ_i Σi得到状态 K j K_j Kj)
- S S S:表示初始状态(是唯一的)
- Z Z Z: 表示一个终态集(不唯一,终止状态可以有多个)
- NFA: M ( K , Σ , f ′ , S ′ , Z ) M(K,Σ,f',S',Z) M(K,Σ,f′,S′,Z)
- K K K:是所有状态的集合(一般状态用大写字母表示)
- Σ Σ Σ:是所有输入符号的集合(一般输入符号用小写字符表示)
- f ′ f' f′:是一个 K × Σ ∗ K×Σ^* K×Σ∗到全体子集的映像(一般表示: K × Σ ∗ → 2 k K×Σ^*\rightarrow{2^{k}} K×Σ∗→2k)
- S ′ S' S′:表示非空初状集(不唯一,在DFA种可以有多个非空初状态)
- Z Z Z: 表示一个终态集(不唯一,终止状态可以有多个)
其实DFA是NFA的一种特殊情况。
两者的主要区别:
- NFA函数关系 f ′ f' f′既可以多值映射又可以单值映射,而DFA中的函数关系 f f f只能单值映射
- NFA的初状态非空不唯一,而DFA初状态非空且唯一
- NFA可以带空(ε)转换,DFA不能
- 什么是确定化?为什么要确定化?
确定化就是将NFA转换成DFA的过程。
在非确定的有穷自动机种(NFA)中,由于状态的转移需要经过若干步,并且每一步都是不可预测的,对后续输入的字符存在一个试探的过程。而在试探的过程中可能会带来重复的步骤,这无疑是增加了程序的运行时间同时降低了工作效率,将NFA转成DFA进行确定化就是为了增加程序的效率缩短工作时间。
- 什么是最小化?为什么要最小化?
DFA的最小化就是寻求状态数最小的与原DFA等价的DFA。
最小化可以降低编译器构造的复杂度、 提高编译器的运行效率
实战例题
- NFA确定化方法:
- 子集法:(假设输入字符集 Z = { a , b } Z=\{a,b\} Z={a,b})
Step1:设置三列: I 、 I a 、 I b I、I_a、I_b I、Ia、Ib
Step2:第一行,求初始态S对ε的推导得到字符集①写入第一列。求对①输入字符ε、a的推导得到字符集 ① ′ ①' ①′写入第二列。求①对输入字符ε、b的推导得到符号集 ① ′ ′ ①'' ①′′写入第三列;
Step3:第二行,观察 ① ′ ①' ①′是否与第一列 I I I有重复,重复则跳过,不重复就写入第二行第一列,重新记作字符集②。求②对字符ε、a的推导得到字符集 ② ′ ②' ②′写入第二列。求②对字符ε、b的推导得到字符集 ② ′ ′ ②'' ②′′写入第三列;
Step4:第三行,以 ① ′ ′ ①'' ①′′为标准进行判断,求相应 I a 和 I b I_a和I_b Ia和Ib所对应的字符集
……持续递推,直到无法产生新的字符集
- 造表法:
- Step1:将NFA的转换图转换成以状态为行,输入为列的图表
- Step2:对原有的状态图进行重新标记
两种方法相比较,我更喜欢造表法,因为它的解题步骤更加简洁,但是对于计算机而言,需要使用子集法来实现
- NFA的最小化:(假设输入字符集 Z = { a , b } Z=\{a,b\} Z={a,b})
- Step1:初始划分,将DFA按照非终态和终态划分成两个集合A,B
- Step2: I a I_a Ia划分,将A,B集合中的元素,按照其 I a I_a Ia属于A还是B进一步划分成A1,A2,B1,B2。
- Step3: I b I_b Ib划分。将A1,A2,B1,B2集合中的元素,按照其 I b I_b Ib属于A1,A2,B1,B2中的哪一个进一步划分成A12,A22,B12,B22
- Step4:上面划分完成的集合重命名为状态0,1,2,3
- Step5:画出相应的状态图,即为最小NFA
附上例题:
例1:
将下图(a)和(b)确定化和最小化。
解 : ( 1 ) 对 图 ( a ) : 解:\\ (1)对图(a): 解:(1)对图(a):
首先可知图(a)是一个NFA,对其进行确定化,如下所示:
将图(a)NAF的状态转换图转换成DAF的矩阵状态转换图:
I I I |
I a I_a Ia |
I b I_b Ib |
{ 0 } \{0\} {0} |
{ 0 , 1 } \{0,1\} {0,1} |
{ 1 } \{1\} {1} |
{ 0 , 1 } \{0,1\} {0,1} |
{ 0 , 1 } \{0,1\} {0,1} |
{ 1 } \{1\} {1} |
{ 1 } \{1\} {1} |
{ 0 } \{0\} {0} |
Ø Ø Ø |
所以图(a)对应的DFA为:
I I I |
I a I_a Ia |
I b I_b Ib |
0 |
1 |
2 |
1 |
1 |
2 |
2 |
0 |
Ø Ø Ø |
得到相应的DFA转换图:(含有终态节点就用双圈)
最小化后的NFA为:
说明:
I I I表示状态集合的ε闭包,可记作: ε − c l o s u r e ( I ) ε-closure(I) ε−closure(I)。大白话就是:初始状态自身以及自身能通过ε到达的状态的集合。
I a I_a Ia表示状态集合的 I I I的 a a a弧转换,可记作: m o v e ( I , a ) , move(I,a), move(I,a),大白话就是: I a I_a Ia集合就是 I I I集合中的元素经过 ε或者a 能到达的状态所组成的集合, I b I_b Ib同理。
解题分析:
由图可知对于状态0,存在函数关系f(0,a)=1、f(0,a)=0,显然状态0对于输入字符a的函数关系f是多值映射,故图(a)是NFA转换图
对于确定化:
- Step1:对于初状态0,因为(a)图中没有ε转换,故集合①就是状态 { 0 } \{0\} {0}
- Step2:此时 I I I={0},此时图中没有 ε ε ε弧,不用管ε,但是有a,状态0经过a可到达状态0和1,所以 I a = { 0 , 1 } I_a=\{0,1\} Ia={0,1},同理可求得 I b = { 1 } I_b=\{1\} Ib={1}
- Step3:观察第一行的 I a I_a Ia是否已存在第一列,显然第一列 I I I中没有存在上一行的 I a I_a Ia,故将它第二行的 I I I中,继续求得这一行的 I a I_a Ia, I b I_b Ib
- Step4:观察第一行的 I b I_b Ib是否已存在第一列,显然第一列 I I I中没有存在上一行的 I b I_b Ib,故将它第二行的 I I I中,继续求得这一行的 I a I_a Ia, I b I_b Ib
- Step5:观察第二行的 I a I_a Ia是否已存在第一列,显然第一列 I I I中已存在 { 0 , 1 } \{0,1\} {0,1},故跳过,进行第二行的 I b I_b Ib判断,经过观察易发现后续的 I a I_a Ia和 I b I_b Ib都是 I I I中已存在的。所以可以得出结论,该DNF已转换成了DNF完成了确定化
- Step6:将 I I I列自上而下重新命名为状态:0、1、2
- Step7:然后将对应的命名填写入 I a I_a Ia和 I b I_b Ib中,即为最终结果
总的来将,NFA的确定化就是递推求解,再对所求集合进行重新命名,最终根据所求表画出相应的DNF状态图的过程
对于最小化:
- Step1::根据集合是否包含终态节点0,可划分为终止态和非终止态 A = { 0 ′ , 1 ′ } A=\{0',1'\} A={0′,1′}和 B = { 2 } B=\{2\} B={2}
- Step2::经过观察可以知道, 0 ′ 0' 0′对应的 I a = 1 ′ ⊆ A , 同 时 1 ′ 对 应 的 I a 同 样 属 于 A I_a={1'}⊆A,同时1'对应的I_a同样属于A Ia=1′⊆A,同时1′对应的Ia同样属于A,故当前无需划分;对于{2}只有一个元素也无需划分
- Step3::同理后续 0 ′ 0' 0′对应的 I b = 1 ′ ⊆ B , 同 时 1 ′ 对 应 的 I b 同 样 属 于 B I_b={1'}⊆B,同时1'对应的I_b同样属于B Ib=1′⊆B,同时1′对应的Ib同样属于B,故当前无需划分
- Step4:当前无可划分集合,划分完成
( 2 ) 对 于 图 ( b ) : (2)对于图(b): (2)对于图(b):
显然可知其本身就是一个DFA,因为他不存在多值映射关系,故不需要确定化。先对其进行最小化:
- Step1:初始划分。 A = { 0 , 1 } , B = { 2 , 3 , 4 , 5 } A=\{0,1\},B=\{2,3,4,5\} A={0,1},B={2,3,4,5}
- Step2: I a 划 分 I_a划分 Ia划分。对于集合A中的元素,由图可知,0对应的 I a I_a Ia是1,1对于的 I a I_a Ia是0,0和1同属于A,故无需划分;对于集合B中的元素,由图可知,2对应的 I a I_a Ia是1,3对应的 I a I_a Ia是3,4对应的 I a I_a Ia是0,5对应的 I a I_a Ia是5,故可进一步划分成集合 B 1 { 2 , 4 } , B 2 = { 3 , 5 } B1\{2,4\},B2=\{3,5\} B1{2,4},B2={3,5}
- Step3: I b 划 分 I_b划分 Ib划分。对于集合A中的元素,,0对应的 I b I_b Ib是2,,1对应的 I a I_a Ia是4,2和4同属于集合B1,故无需划分,同理可知B1,B2中的元素也无需划分,划分完成
- Step4:将划分的集合重新编号0,1,2,根据划分画出相应的状态转换图,如下:
例2:
将下图的NFA确定化:
例3:
将图中的DFA最小化