编译原理之如何绘制NFA状态图

本文深入解析NFA状态图设计,涵盖空串驱动、核心状态转换及NFA到DFA的转换过程,包括闭包求解、状态集对应及DFA状态最小化,适合初学者和复习者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NFA状态图设计到很多的空串驱动,无论是刚开始学还是一段时间没看,都会搞不清楚,以此文作为记录

NFA其实核心就是三种状态

r=s|t
在这里插入图片描述

r=st
在这里插入图片描述

r=s*
在这里插入图片描述

方法

其余的所有表达式都是以上三种的集合,所以我们要做的,是两点

1、记清楚三种表达式

2、区别清楚搭配的时候哪个状态和哪个状态是一致的

我们来看例子

r=(s|t)*
这显然是其中两种的组合,括号优先,我们先画括号里面,同时也分析外面
在这里插入图片描述
可以发现,下面的0和5作为s|t最外层的始末状态,就是(s|t)最内层的始末状态,所以两者相对应合成一个
在这里插入图片描述

再来一个稍难的
(ϵ\epsilonϵ|a)b*
可以看到这是 r=s|t 与r=s的合体
在这里插入图片描述
如图所示,本来1状态时初始状态,但是加了括号之后,他成为(ϵ\epsilonϵ|a)的内部初始状态,而不是整个表达式的初始状态
同时6状态作为(ϵ\epsilonϵ|a)的结束状态,是无缝成为b
的开始状态的,因为6状态对于b来说是“其他状态的结束状态,或者是b的外部开始状态”,然后通过空串驱动而来,b的核心状态时7和8,9是“b*的外部结束状态”,所以也可作为其他状态的开始状态

总结一下 任何表达式的开始状态和结束状态都可以直接使用 r=s*的开始状态和结束状态

当然了,上式其实是可以化简的,注意到1,2,3,6之间的驱动都是ϵ\epsilonϵ
在这里插入图片描述
两者对比如上,由于ϵ\epsilonϵ直接化简,两者也不需要通过ϵ\epsilonϵ驱动来区分,2,4,状态也将省略


接下来是将NFA转换为DFA的过程,需要求出闭包
NFA的状态集对应一个DFA的状态,画表,然后绘制DFA,最后再最小化DFA的状态数量,即可画出一个DFA

这就是词法分析器的核心思想

### 编译原理NFA 转 DFA 的状态转换图实现 以下是基于 Python 实现的一个简单的 NFA 到 DFA 转换的代码示例。此代码实现了子集构造法的核心逻辑,用于将非确定有限自动机 (NFA) 转换成确定有限自动机 (DFA)[^1]。 ```python from collections import deque, defaultdict def epsilon_closure(states, transitions): """计算给定状态集合的 ε-closure """ closure = set(states) stack = list(states) while stack: current_state = stack.pop() if 'ε' in transitions[current_state]: for next_state in transitions[current_state]['ε']: if next_state not in closure: closure.add(next_state) stack.append(next_state) return frozenset(closure) def move(states, char, transitions): """ 计算从一组状态出发经过指定字符可以到达的状态集合""" result = set() for state in states: if char in transitions[state]: result.update(transitions[state][char]) return frozenset(result) def nfa_to_dfa(nfa_states, nfa_transitions, start_state, final_states): """ 将 NFA 转换为 DFA """ dfa_states = [] dfa_transitions = {} dfa_start_state = None dfa_final_states = [] # 初始化 DFA 开始状态 eclosure_start = epsilon_closure([start_state], nfa_transitions) queue = deque([eclosure_start]) visited = {eclosure_start} if any(state in final_states for state in eclosure_start): dfa_final_states.append(eclosure_start) dfa_start_state = eclosure_start dfa_states.append(dfa_start_state) while queue: current_set_of_states = queue.popleft() for input_symbol in sorted(set().union(*[nfa_transitions[s].keys() for s in current_set_of_states]) - {'ε'}): reachable_states = move(current_set_of_states, input_symbol, nfa_transitions) new_eclosure = epsilon_closure(reachable_states, nfa_transitions) if new_eclosure and new_eclosure not in visited: visited.add(new_eclosure) queue.append(new_eclosure) dfa_states.append(new_eclosure) if any(state in final_states for state in new_eclosure): dfa_final_states.append(new_eclosure) if current_set_of_states not in dfa_transitions: dfa_transitions[current_set_of_states] = {} if new_eclosure: dfa_transitions[current_set_of_states][input_symbol] = new_eclosure return { "dfa_states": dfa_states, "dfa_transitions": dfa_transitions, "dfa_start_state": dfa_start_state, "dfa_final_states": dfa_final_states } # 示例 NFA 定义 nfa_states = ['q0', 'q1', 'q2'] final_states = ['q2'] transitions = { 'q0': {'a': ['q0'], 'b': ['q1'], 'ε': ['q1']}, 'q1': {'a': ['q2']}, 'q2': {}, } start_state = 'q0' result = nfa_to_dfa(nfa_states, transitions, start_state, final_states) print("DFA States:", result["dfa_states"]) print("DFA Transitions:") for key, value in result["dfa_transitions"].items(): print(f"{key}: {value}") print("Start State:", result["dfa_start_state"]) print("Final States:", result["dfa_final_states"]) ``` 上述代码展示了如何利用子集构造法完成 NFA 向 DFA 的转化过程[^3]。其中 `epsilon_closure` 函数负责处理 ε 移动闭包的操作,而 `move` 函数则用来获取某一组状态下通过特定输入符号可达到的新状态集合。 #### 关键点说明 - **Epsilon-Closure**: 对于每一个 NFA 状态,都需要先求其对应的 ε-closure 集合,即可以通过任意数量的 ε 过渡访问到的所有可能状态。 - **Move Function**: 给定当前的一组状态以及某个具体的输入符号,该函数返回能够直接跳转至的目标状态集合。 - **Subset Construction Algorithm**: 使用队列来遍历尚未探索过的状态组合,并逐步构建完整的 DFA 表格结构。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值