答案 0 :(得分:3)
NFA没有“ε状态”。它们具有“epsilon过渡”:使用epsilon字母标记的过渡,表示该过渡不消耗任何输入字符。 NFA图不需要包含任何epsilon转换。
Epsilon转换由编译器生成,该编译器将正则表达式转换为NFA图。它们有助于表示与可选匹配对应的旁路路径。如果您有一个没有任何可选项的正则表达式,例如ab
,则NFA图表不会(必须)包含任何epsilon边缘。
NFA模拟和NFA到DFA转换的一个重要概念是“epsilon闭包”:一组状态可通过跟随epsilon转换从状态到达。如果任何状态S在闭包中,并且该状态具有到某个状态T的epsilon转换,那么T也在闭包中。因此“epsilon关闭”。
我们构造了一组NFA状态来处理NFA图在同一输入字符上有多个转换到多个状态的模糊性。然后我们执行epsilon闭包来处理存在转换的额外歧义而不消耗输入符号,表示可选匹配。
NFA模拟动态构造NFA状态集; NFA到DFA“子集构造”预先计算这些集合,并将它们转换为DFA图形中的节点。
要将您的NFA图表转换为DFA,我们首先从空白平板开始。我们没有NFA国家。箭头告诉我们NFA从状态1开始。我们问自己,NFA状态在由状态1组成的集合的epsilon闭包中是什么?我们注意到:没有epsilon过渡。所以闭包集是{ 1 }
。到目前为止,我们的DFA计算机为空,因此我们将此集{ 1 }
设为S0
,并将该对象称为a
:DFA的初始状态。
既然我们有DFA状态,我们会问自己:对于每个输入字母字符,哪些转换超出此状态?我们首先评估S0
。从代表NFA状态{ 1 }
的集a
开始,我们计算可在符号{ 1, 2 }
上到达的NFA状态集。这些状态为1
,因为a
在a
上指向自身,并在{ 1, 2 }
上转换为2。设置此转换后,我们需要考虑epsilons:我们需要通过计算其epsilon闭包来扩展该集合。由于没有epsilons,所以无所事事。我们有S1
,我们会将该状态称为DFA的州 a b NFA set
S0: S1 ? { 1 }
S1: ? ? { 1, 2 }
。到目前为止,我们已经有了DFA的新图片:
S0
我们知道S1
上的a
转换为b
。我们还不知道它对S1
的作用,我们还没有考虑过b
的转换。
我们接下来转到b
(在评估S0的背景下)。在{ 1 }
上,{ 2 }
之外的状态可由{ 2 }
集合组成。再次,epsilon-closing对此没有任何作用。并且S2
看起来不像任何现有的DFA状态,因此我们建立了新状态 a b
S0: S1 S2 { 1 }
S1: ? ? { 1, 2 }
S2: ? ? { 2 }
:
S0
现在我们已完成S1
,因此我们转到下一个未完成状态{ 1, 2 }
,其中包含NFA集a
。我们问,在消耗{ 1, 2 }
时,可以从这个集合中获得哪些州?答案是{ 1, 2 }
。这个epsilon闭包是{ 1, 2 }
。我们注意到:S1
与S1
相同。因此,a
在 a b
S0: S1 S2 { 1 }
S1: S1 ? { 1, 2 }
S2: ? ? { 2 }
上转换为自身:
S1/b
然后我们考虑{ 1, 2 }
。消费b
的{{1}}可以达到什么样的集合?答案是:{ 1, 2 }
。因此,S1
也会在b
上转换为自身。
a b
S0: S1 S2 { 1 }
S1: S1 S1 { 1, 2 }
S2: ? ? { 2 }
现在S2/a
很有趣。 {2}在a
上没有任何转换:集合为空。我们可以用各种方式表示这种情况,其中之一就是我们创建了一个名为E
的集合(错误)。如果在状态S2中看到a
,那么这是一个错误;机器不接受这个角色。
a b
S0: S1 S2 { 1 }
S1: S1 S1 { 1, 2 }
S2: E ? { 2 }
E: { }
对于S2/b
,我们看到{ 2 }
过渡到{ 1 }
而{ 1 }
只是S0
:
a b
S0: S1 S2 { 1 }
S1: S1 S1 { 1, 2 }
S2: E S0 { 2 }
E: { }
如果机器进入状态E
,它就会卡在那里,所以我们可以像这样填写条目:
a b
S0: S1 S2 { 1 }
S1: S1 S1 { 1, 2 }
S2: E S0 { 2 }
E: E E { }
最后,我们注意到在原始NFA中,状态2是接受状态。因此,在DFA中,NFA集包含状态2的任何状态都是接受状态。
a b acc?
S0: S1 S2 { 1 }
S1: S1 S1 y { 1, 2 }
S2: E S0 y { 2 }
E: E E { }
如果机器进入状态E,则表示永久性故障。 (向DFA提供输入的人可能会注意到这种情况并停止喂食。)