NFA 到 DFA 转换的简明描述?

Posted

技术标签:

【中文标题】NFA 到 DFA 转换的简明描述?【英文标题】:A succinct description of NFA to DFA conversion? 【发布时间】:2011-05-25 23:19:08 【问题描述】:

比我更聪明的人可以向 SO 社区简洁地描述 NFA 到 DFA 的转换算法吗? (最好是 500 字或更少。)我看到的图表和讲座只会混淆我以为我曾经知道的东西。我最有信心从状态图中生成初始 NFA 转换表,但在那之后,我丢失了 epsilons 和子集中的 DFA。

1) 在转换(增量)表中,哪一列代表新的 DFA 状态?它是生成状态的第一列吗?

2) 在下面示例的第 2,3 行第 0 列中,2,3 对 NFA 的状态图意味着什么? (抱歉,我必须在图片中思考。)我认为这将是 DFA 中的“输入 0 的回送”?

3) 从表格到 DFA 或识别结果 DFA 的接受状态是否有任何简单的“经验法则”?

无限自主

delta  |  0    |  1     |
=======+=======+========+
1    |1    |2     |
2    |3    |2,3   |
3    |2    |2,4   |
2,3  |2,3  |2,3,4 |
2,4  |3,4  |2,3,4 |
2,3,4|2,3,4|2,3,4 |
3,4  |2,4  |2,4   |

编辑:这是dot format 中的上表,为 Regexident 加油。

digraph dfa 
    rankdir = LR;
    size = "8,5"
/*  node [shape = doublecircle]; "1";*/
    node [shape = circle];

    "1" -> "1" [ label = "0" ];
    "1" -> "2" [ label = "1" ];

    "2" -> "3"   [ label = "0" ];
    "2" -> "2_3" [ label = "1" ];

    "3" -> "2"   [ label = "0" ];
    "3" -> "2_4" [ label = "1" ];

    "2_3" -> "2_3"   [ label = "0" ];
    "2_3" -> "2_3_4" [ label = "1" ];

    "2_4" -> "2_3"   [ label = "0" ];
    "2_4" -> "2_3_4" [ label = "1" ];

    "2_3_4" -> "2_3_4" [ label = "0" ];
    "2_3_4" -> "2_3_4" [ label = "1" ];
    "3_4" -> "2_4" [ label = "0" ];
    "3_4" -> "2_4" [ label = "1" ];

这里是渲染的形式:

注意:该表缺少有关州接受度的任何信息,因此图表也是如此。

【问题讨论】:

00ps,我忘记了我的例子。让我快点打它... 【参考方案1】:

当您从 NFA 构建 DFA 时,您基本上会找到 NFA 可以在一段时间内出现的那些状态集(例如模拟 NFA)。首先,您从起始状态开始,然后找到可以通过 epsilon 转换到达的所有状态。这组状态构成了最终 DFA 的起始状态。然后你跟随这个状态集的传出转换。这些可能会导致另一个 NFA 状态,因为您发现这些状态可以通过 epsilon 输入再次到达,并且您将获得另一组 NFA 状态,这将是一个新的 DFA 状态。您一直执行此过程,直到完成为止。

关键是,生成的 DFA 状态将成为旧 NFA 状态的集合,它们是兼容的(关于 epsilon 转换)。这些集合也可能重叠,这没有错误。现在我可以回答你的问题了:

1) 第一列代表新的 DFA 状态。它显示了构成给定 DFA 状态的 NFA 状态集。

2) 你的假设是正确的,这意味着在 0 输入上环回状态 2,3。

3) DFA 表可以很容易地从这个表中构造出来,只需用字母命名你的状态。任何包含至少一个 NFA 接受状态的 DFA 状态也将成为 DFA 中的接受状态。

我希望我已经足够清楚了。

【讨论】:

RE: 2) 原始 NFA 是什么意思? RE: 3) 所以如果 4 在上面的例子中是一个接受状态,那么对应的 DFA 接受状态是 2,4、2,3,4 和 3,4 2) 您可以从中读取的所有信息是,从 NFA 状态 2 或 3,在 0 输入(或一些 epsilon 转换)上,您可以达到状态 2 或 3。这并不多,但可以确定自动机是一个单向过程,一些信息会丢失。 3) 没错,我在笔记里查过了,现在我完全确定了:) “部分信息丢失”是什么意思?什么信息?【参考方案2】:

核心思想大概是理解DFA是一种叠加在NFA之上的机器。虽然 NFA 在节点数量或它与问题的关系方面更简单,但它的规则非常微妙和复杂(它进入 正确 状态,无论哪种情况)。 dfa 在它包含的节点方面要复杂得多,但规则非常简单,因为对于任何给定的输入都只有一个输出状态。

转型非常严格。 DFA 中的每个状态都是 NFA 中状态的子集。 DFA的起始状态是只包含NFA的起始状态的集合,DFA的接受状态是它所有以NFA的接受状态为元素的状态。

DFA 中的转换是唯一棘手的部分。 NFA 是非确定性的,因为它对于给定输入的输出状态是一组状态,但 DFA 有一组对应的 NFA 状态作为它自己的状态,表示自动机可以的 NFA 状态中的哪一个> 进入。因此,任何给定输入的任何 DFA 状态的输出状态是该 DFA 状态的所有 NFA 状态的输出状态的联合

就实际实施而言,DFA 的州人口基本上是 NFA 州的权力集。 IE,n NFA 状态为 2^(n)。在实践中,它通常要小得多,但没有通用的方法来预测它的大小,因此一些实用的 NFA 到 DFA 实现会在到达 DFA 状态时动态生成它们并缓存它们。一旦创建了一定数量的状态,就会丢弃最近最少使用的状态,从而限制缓存的大小。

【讨论】:

【参考方案3】:

假设输入 NFA 是 (S, Q, q0, T, F) 其中 S 是输入符号集,Q 是状态集,q0 是开始状态,T 是转换集,F是接受状态的集合。每个转换都是一个三元组 (q, s, r),其中 q 和 r 是状态,s 是长度为 0 或 1 的字符串。

对于任何有限字符串 s,令 D(s) 是所有状态的集合,这些状态可以从 q0 沿着一条转换路径到达,其标签连接在一起形成 s。

算法需要做的是构造一个确定性自动机,其状态是 Q 的子集,并且对于任何字符串 s,DFA 最终都会处于状态 D(s)。

如果是这样,那么任何包含 NFA 接受状态的 DFA 状态都应该是 DFA 的接受状态。

考虑空字符串,epsilon; D( “” ) 将是 q0 的 epsilon-closure,即您可以从 q0 到达的所有状态,仅遵循标有空字符串的转换。我们称其为 Set Q0。 (在您的示例中为 D(“”)=1。)现在我们“探索”该状态,这意味着:对于每个输入符号 a,您找出该符号的转换位置,离开状态应该去哪里。这会导致您发现更多需要在 DFA 中的状态。 (在您的示例中 S=0,1,因此这些状态将是 D(“0”)=1 和 D(“1”)=2。但 D(“0”) 与D“”);所以这不是新的。因此,现在唯一已发现但尚未探索的状态是 D(“1”)。)继续探索状态,直到没有更多已发现但尚未探索的状态。

【讨论】:

以上是关于NFA 到 DFA 转换的简明描述?的主要内容,如果未能解决你的问题,请参考以下文章

利用子集构造法实现NFA到DFA的转换

用c++实现,NFA到DFA的转换,请教高手。

将字符集转换为 nfa/dfa 的高效算法

编译原理:怎么用子集法将NFA转换成DFA? 用图4.16的NFA举例子

编译原理-第三章 词法分析-3.7 从正则表达式到自动机-从NFA到DFA的转换

NFA转换为等价的DFA