编译原理:打包思维-NFA 怎么变成 DFA

像讲故事一样:NFA 怎么变成 DFA

在编译原理里,非确定有限自动机(NFA)和确定有限自动机(DFA)是两个好朋友。NFA 像个随性的向导,可以同时走多条路,而 DFA 像个严格的老师,每步只许走一条路。为了让 NFA 的"随性"变成 DFA 的"规矩",我们得学会一个"整理魔法"。别担心,这个过程没那么复杂,我们用一个简单的故事和例子,手把手带你看明白!

一、故事开场:为什么要变?

想象你在森林里跟着一个向导(NFA)找宝藏。他看到一条岔路说:"可以走左边,也可以走右边,甚至还能跳过去试试。"你得派好几个分身去试每条路,看哪个能到宝藏。这很灵活,但太乱了。如果能把这些乱七八糟的路线整理成一张简单地图(DFA),上面写着"看到这个就去那儿",找宝藏就轻松多了。

在计算机里,NFA 是从正则表达式来的,很容易做出来,但它"分身太多"不好用。DFA 每步只有一条路,电脑喜欢,所以我们要把 NFA 变成 DFA。

二、主角登场:一个简单的 NFA

我们用一个简单的例子:识别"以 a 开头,后面跟任意多个 b"(正则表达式 ab*)。它的 NFA 长这样:

  • 有三个点:起点 q0,中间点 q1,宝藏点 q2
  • 路线:
    • q0 看到 a 可以去 q1
    • q1 看到 b 可以回到 q1(循环)。
    • q1 啥也不看(空跳)也能到 q2
  • 起点是 q0,宝藏在 q2

这个 NFA 很随性:读到 b 时可以循环,可以跳,挺自由的。

三、整理思路:从乱到整齐

要把 NFA 变成 DFA,我们得解决它的"随性"。NFA 的问题是:一个点读一个字母,可能去好几个地方,还能空跳。我们要做的,就是把所有"可能去的地方"打包成一个大点,让每步只有一条路。

比喻:

  • NFA 像个向导说:"读到 a,你可以去这儿那儿。"
  • DFA 像个老师说:"读到 a,你就去这个大包裹,里面装了所有可能的地方。"

这个"打包"的过程,就是把 NFA 的多个可能性合起来,变成 DFA 的一个状态。

四、动手整理:一步步来

我们拿 ab* 的 NFA 来试试,假装自己在画新地图。

第一步:从起点开始

  • NFA 起点是 q0。问:"从 q0 能空跳到哪儿?" 答案是没有空跳,所以 DFA 的起点就是"装着 q0 的包裹",记作 {q0}

第二步:读字母,看去哪儿

  • {q0}a
    • NFA 说:q0 --a--> q1
    • q1 能空跳到 q2q1 --ε--> q2)。
    • 所以,把所有能到的地方打包:{q1, q2}
    • 新地图写:{q0} --a--> {q1, q2}
  • {q0}b
    • NFA 说:q0 没路。
    • 所以没新地方,暂时不管。

第三步:从新包裹继续

  • 现在有了 {q1, q2},从它读 b
    • q1 --b--> q1q2 没路。
    • q1 还能空跳到 q2
    • 打包:还是 {q1, q2}
    • 新地图写:{q1, q2} --b--> {q1, q2}(自己到自己)。
  • {q1, q2}a
    • q1q2 都没路。
    • 所以没新地方。

第四步:定下宝藏

  • NFA 的宝藏在 q2
  • DFA 只要包裹里有 q2,就是宝藏点。
  • {q1, q2}q2,所以它是宝藏点。

新地图(DFA):

  • 两个点:{q0}{q1, q2}
  • 路线:
    • {q0} --a--> {q1, q2}
    • {q1, q2} --b--> {q1, q2}
  • 起点:{q0}
  • 宝藏:{q1, q2}

五、试试看:新地图好用吗?

  • 输入 a:从 {q0} --a--> {q1, q2},到宝藏,成功!
  • 输入 ab{q0} --a--> {q1, q2} --b--> {q1, q2},还是宝藏,成功!
  • 输入 b:从 {q0} 没路,失败。

跟 NFA 一样能认出 ab* 的东西,但每步只有一条路,简单多了!

六、整理的秘密:打包和空跳

这个"魔法"的关键是两点:

  1. 打包:把 NFA 所有可能的状态装进一个包裹,变成 DFA 的一个点。
  2. 空跳 :每次算新包裹时,别忘了 NFA 的空跳(像 q1 --ε--> q2),得把能跳到的地方也装进去。

这个过程就像把向导的口头建议整理成一张表格,告诉你在哪儿读到什么就去哪儿。

七、为什么这么做?

在编译器里,NFA 是从正则表达式来的,但它太"随性",电脑跑起来得试所有分身,太慢。DFA 每步只有一条路,电脑一看就知道下一步,很快。所以我们用这个方法,把 NFA 变成 DFA,让词法分析又快又准。

八、总结:从故事到领悟

NFA 像个随性的向导,DFA 像个严格的老师。把 NFA 变成 DFA,就是把所有"可能"打包成"一定",从乱七八糟的路线变成一张简单地图。用 ab* 的例子,我们一步步整理,看到它怎么从三个点变成两个包裹,每步都清清楚楚。

下次再看到代码被编译器读懂时,想想这个小故事:从随性到规矩的魔法,就藏在里面!

相关推荐
景天科技苑6 小时前
【Rust通用集合类型】Rust向量Vector、String、HashMap原理解析与应用实战
开发语言·后端·rust·vector·hashmap·string·rust通用集合类型
小钻风巡山8 小时前
springboot 视频分段加载在线播放
java·spring boot·后端
豌豆花下猫8 小时前
Python 潮流周刊#100:有了 f-string,为什么还要 t-string?(摘要)
后端·python·ai
小黑随笔8 小时前
【Golang玩转本地大模型实战(一):ollma部署模型及流式调用】
开发语言·后端·golang
江沉晚呤时8 小时前
Redis缓存穿透、缓存击穿与缓存雪崩:如何在.NET Core中解决
java·开发语言·后端·算法·spring·排序算法
光影少年10 小时前
新手学编程前端好还是后端
前端·后端
why15110 小时前
百度网盘golang实习面经
开发语言·后端·golang
hac132212 小时前
SpringBoot多环境配置
java·spring boot·后端
Go高并发架构_王工15 小时前
GoFrame框架深度解析:grpool的优势、最佳实践与踩坑经验
服务器·后端·golang
exe45216 小时前
4 月 28 日项目进展与规划会议纪要
后端