我在这个网站上发现了同样的问题,答案是PDF describing how to convert an NFA to a regex。但这不起作用,因为这种方法有一些条件:
在我的例子中,开始状态只是进入下一个状态而不是所有状态(例如q0进入q1但不进入q2,q3),并且转换到开始状态。
那么将NFA转换为正则表达式的最简单方法是什么?我没有给出一个NFA示例,因为我没有特定的一个,只是一个普遍的问题,因为我遇到了这种DFA,其中启动状态与所有状态都没有关联,并且转换为开始状态。
我想要一种通用算法来转换这种NFA。
答案 0 :(得分:2)
答案是假设这些条件,因为可以修改任何NFA以满足这些要求。
对于任何类型的NFA,您可以添加一个新的初始状态q 0 ,它具有到原始初始状态的epsilon转换,并且还使用一个名为∅的附加转换符号(它们称之为空集符号,假设是与原始NFA中的任何符号不匹配的符号,从它到任何其他状态,然后使用这个新状态作为新的初始状态。请注意,这不会更改原始NFA接受的语言。这将使您的NFA满足第一个条件。
对于任何类型的NFA,您可以添加新的接受状态q a ,其具有来自原始NFA中所有接受状态的epsilon转换。然后将此标记为唯一的接受状态。请注意,这不会更改原始NFA接受的语言。这将使您的NFA满足第二个条件。
通过上述结构,通过设置q 0 != q a ,它满足第三个条件。
在您提供的链接中,第四个条件通过一个名为∅(空集符号)的特殊转换符号来解释,其中原始NFA中的实际字母不能匹配。因此,您可以使用此新符号将转换从每个状态添加到任何其他状态。请注意,这不会更改原始NFA接受的语言。
所以现在修改了NFA以满足这四个要求,您可以在那里应用算法将NFA转换为正则表达式,它将接受与原始NFA相同的语言。
编辑以回答进一步的问题:
要在评论中回答您的问题,请考虑具有两种状态的NFA,q A 和q B 。 q A 是初始状态以及唯一的接受状态。我们有一个从q A 到符号为0的自身的转换。我们也从q A 到q B 转换为符号1.最后我们从q B 转换到q A with symbol 0。
可视化:
0,1 | 1 ->qA----->qB ^ | |-------| 0
步骤2.当我们规范化NFA时,只需将新的初始状态(q init )指向q A ,并设置新的接受状态(q来自q A 的 acc 。
步骤3.我们要删除q A 。所以q A 是算法中的q rip (第3页)。现在我们需要考虑进入q A 的每个状态以及从q A 退出的每个状态。在这种情况下,有两个状态指向q A ,即q init 和q B 。 q A 指向两种状态,即q B 和q acc 。通过该算法,我们用中的过渡q 替换 - > q rip - > q out 中的过渡q / sub> - > q out ,在中具有转换符号R dir + R (R rip ) * R out ,其中:
所以在这种情况下,我们用q init替换转换q init - > q A - > q B - > q B ,带有转换符号(0 + 1)* 1。继续这个过程,我们将创建总共4个新过渡:
然后我们可以删除q A 。
步骤4.我们要删除q B 。同样,我们识别中的q 和q out 。这里只有一个状态来到q B ,这是q init ,只有一个状态偏离q B ,这是q <子> ACC 子>。所以我们有:
所以新的转换q init - &gt; q acc 将是:
[R <子> DIR 子> + R <子>在子>(R <子>撕裂子>)* R <子>出子>
(0 + 1)* +(0 + 1)* 1(0(0 + 1)* 1)* 0(0 + 1)*
我们可以删除q B 。
步骤5.由于原始NFA中的每个州都已被删除,我们就完成了。所以最终的正则表达式如上所示。
请注意,最终的正则表达式可能不是最优的(并且在大多数情况下它不会是最优的),这可以从算法中得到预期。一般来说,找到NFA(甚至是DFA)的最短正则表达式是非常困难的(尽管对于这个例子,很容易看出第一个组件已经覆盖了所有可能的字符串)
为完整起见,接受相同语言的最短正则表达式将是:
(0 + 1)*