【程序语言与编译】NFA转DFA(子集构造法)

适合读者:软考中级备考同学

阅读时间:4分钟

内容:子集构造法原理、算法步骤、示例、例题


1. 为什么需要NFA转DFA?

NFA(非确定有限自动机)构造直观,但直接模拟运行效率较低(需要回溯或并行跟踪多个状态)。DFA(确定有限自动机)每个输入符号唯一确定下一状态,模拟运行速度快,更易于硬件实现或编程。

理论 :NFA和DFA的识别能力等价------任何NFA都可以转换为等价的DFA。转换的标准算法称为子集构造法(Subset Construction)。

软考中常考查子集构造法的基本思想或简单实例的转换。


2. 核心概念:ε-闭包

在NFA中,允许不读入任何输入符号(ε)就转移状态。转换前需要先理解ε-闭包:

  • ε-闭包 (ε-closure):从某个状态出发,通过0条或多条ε转移所能到达的所有状态的集合。
  • 例如:状态A有ε边到B,B有ε边到C,则 ε-closure({A}) = {A, B, C}。

3. 子集构造法算法步骤

目标:构造一个DFA,使得它接受的字符串集合与原NFA完全相同。

  1. 初始化

    • 计算NFA初始状态的ε-闭包,记为 S0。这个 S0 就是DFA的初始状态。
    • 将 S0 加入未处理队列,并作为DFA的一个状态。
  2. 对每个未处理的DFA状态(即NFA状态子集),处理所有输入符号

    假设当前DFA状态为 T(T 是一个 NFA 状态子集)。对于每个输入符号 a(通常来自字母表 Σ):

    • 计算 move(T, a):从 T 中任一状态出发,读入一个 a 所能到达的所有NFA状态的集合。
    • 计算 ε-closure(move(T, a)),得到一个新的NFA状态子集 U。
    • 如果 U 不为空,且尚未在DFA中出现过,则将 U 作为一个新的DFA状态加入队列。
    • 记录DFA中从 T 到 U 在输入 a 下的转移。
  3. 标记终止状态

    如果DFA的某个状态(即NFA状态子集)中包含NFA的至少一个终止状态,那么该DFA状态为终止状态。

  4. 重复直到所有状态都处理完毕。


4. 示例:NFA转DFA

4.1 原NFA描述

  • 状态:A(初始),B,C(终止)。
  • ε转移:无。
  • 转移:
    • A 读 0 → A 和 B
    • A 读 1 → A
    • B 读 1 → C
  • 其他转移无。

这个NFA识别所有以 01 结尾的串。

4.2 转换过程

第1步:初始状态 ε-closure({A}) = {A}(无ε转移)。记为 D_A = {A}。

第2步:处理 D_A = {A}:

  • 输入 0:move({A},0) = {A, B},ε-closure({A,B}) = {A, B} → 新状态 D_{AB} = {A, B}
  • 输入 1:move({A},1) = {A},ε-closure({A}) = {A} → 已存在 D_A

第3步:处理 D_{AB} = {A, B}:

  • 输入 0:move({A,B},0) = {A, B}(A→A,B;B无0),闭包 {A,B} → 已有 D_{AB}
  • 输入 1:move({A,B},1) = {A, C}(A→A;B→C),闭包 {A, C} → 新状态 D_{AC} = {A, C}

第4步:处理 D_{AC} = {A, C}:

  • 输入 0:move({A,C},0) = {A, B}(A→A,B;C无0),闭包 {A,B} → 已有 D_{AB}
  • 输入 1:move({A,C},1) = {A}(A→A;C无1),闭包 {A} → 已有 D_A

第5步:标记终止状态。原NFA的终止状态是C。在DFA状态中,D_{AC} 包含C,因此 D_{AC} 是终止状态。

4.3 得到的DFA

  • 状态:D_A(初始),D_{AB},D_{AC}(终止)
  • 转移:
    • D_A 读0 → D_{AB};读1 → D_A
    • D_{AB} 读0 → D_{AB};读1 → D_{AC}
    • D_{AC} 读0 → D_{AB};读1 → D_A

可重新命名:将 D_A 命为 q0,D_{AB} 命为 q1,D_{AC} 命为 q2。


5. 简化技巧与注意事项

  • ε闭包 是子集构造法的关键,务必先计算所有状态的ε闭包。
  • 如果NFA没有ε转移,那么每个状态子集的ε闭包就是它本身,过程会简单很多。
  • DFA的状态数在最坏情况下可能是指数级(相对于NFA状态数),但实际题目中通常很小。
  • 考试中常考的是简单NFA(2~4个状态)的转换,只需按步骤逐步推导即可。

6. 经典例题

题目1:已知NFA的转移表如下(无ε转移):

状态 输入a 输入b
0 {0,1} {0}
1 {2} {2}
2 {} {}

初始状态0,终止状态2。用子集构造法转换为DFA。

解:

  • 初始闭包 {0} → D0
  • D0 读a:move({0},a)={0,1} → D01
  • D0 读b:move({0},b)={0} → D0
  • D01 = {0,1} 读a:{0,1}→{0,1,2}(0→0,1;1→2)→ D012
  • D01 读b:{0,1}→{0,2} → D02
  • D012 = {0,1,2} 读a:{0,1,2}→{0,1,2} → D012
  • D012 读b:{0,1,2}→{0,2} → D02
  • D02 = {0,2} 读a:{0,2}→{0,1} → D01
  • D02 读b:{0,2}→{0} → D0
  • 终止状态:包含原终止状态2的DFA状态:D012, D02。

答案:DFA有4个状态:D0(初始),D01,D012(终止),D02(终止)。


题目2 (概念):子集构造法的作用是( )。

A. 将DFA转化为NFA

B. 将NFA转化为等价的DFA

C. 最小化DFA

D. 消除ε转移

答案:B


7. 记忆口诀

NFA转DFA,子集构造法。
初态闭包起,每个符号算。
移动取闭包,新集加进来。
含终态即终态,确定化完成。


8. 给备考同学的一句话

子集构造法是软考中有限自动机部分的进阶考点。理解ε-闭包 和move两个操作,按步骤逐步推导,就能完成转换。考试中一般不会要求处理过于复杂的NFA,掌握教材上的简单例子即可。如果遇到选择题,记住"子集构造法"这个名字及其作用(NFA→DFA)就能得分。


🔔 本专栏日更2篇,点击头像 → 专栏《软考中级高频考点》订阅

#软考中级 #软件设计师 #NFA转DFA #子集构造法 #有限自动机

相关推荐
Java后端的Ai之路9 小时前
06-React-Props
前端·react.js·前端框架
滕州市燕猫虎计算机科技工作室个体工商户9 小时前
《Rust程序设计》学习笔记八:结构体
笔记·学习·rust·rust程序设计
Flynt9 小时前
开源"间谍卫星"说数据全是真的,我把它的免key数据源挨个试了一遍
前端·开源·数据可视化
Csvn10 小时前
渲染管线
前端
程序员大阳10 小时前
副队长CSS教程(33)–圆角与透明
前端·css·透明·圆角
志尊宝10 小时前
Vue3 零基础每日笔记(082):文件上传实战——el-upload 校验、自定义上传、头像预览
前端·javascript·vue.js·笔记·#javascript·#vue.js
鬼手点金11 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
柳杉11 小时前
借助 Codex 和可视化工作流,从调研到完整实现,3D 大屏竟然可以这么简单
前端·ai编程·数据可视化
IMPYLH11 小时前
HTML 的 <wbr> 元素
前端·html
后季暖11 小时前
电商问数笔记(2)
笔记