NFA 与 DFA 的转换——详解子集构造算法

NFA 与 DFA 的转换

a(b|c)* 的 NFA 图

今天我就要把上面这个图转换成 DFA

0X00 为什么要这么做

一旦有不确定的状态转换就会涉及「回溯」

一旦涉及「回溯」

就代表无用功,就代表无用的迭代,因此我们要避免回溯。

0X01 伪代码

q0 <- eps_closure (n0)
Q <- {q0}
workList <- q0
while (workList != [])
    remove q from workList
    foreach (character c)
        t <- eps_closure(delta (q, c))
        D[q, c] <- t
        if (t not in Q)
            add t to Q and workList

<- 是赋值

0X02 详解伪代码

  • 伪代码的第一步就是求 n0 的 eps_closure,可以得到 q0 = {1}

首先什么是 eps_closure

先有个感性的认识,求 2 的 eps_closure

{2, 3, 5}

4 的 eps_closure:

{4, 5, 3}

根据上面两个例子:

可以很感性地认识到一个节点的 eps_closure 就是一个节点不需要其他输入时,所能到达的所有节点

而求 eps_closure 很容易用「深度优先搜索」来得到。

  • 来到代码第 8 行:计算闭包 q 中增加一个字符以后的新的闭包

比如 q0 从 worklist 中拿出以后,可以和 a 结合得到 n1。那么由 n1 计算出来的新闭包就是q1 {2, 3, 5}

  • 代码第 9 行:D[q, c] 记录下这个关系
  • 如果这个闭包 t 是没出现过的就加入 Q 和 worklist 中

最后

worklist 为 空

Q 为 {q0, q1, q2, q3}

q0 = {1}

q1 = {2, 3, 5}

q2 = {3, 4, 5}

D 是记录关系的表

D[q0, a] = q1

D[q1, b] = q2

D[q1, c] = q2

D[q2, b] = q2

D[q2, c] = q2

注:我也是看的华老师的《编译原理》但是画 NFA,DFA 的方法有些不一样。

你可能感兴趣的:(NFA 与 DFA 的转换——详解子集构造算法)