参考资料
自动机从ε NFA到DFA的转换
Step1
构建ε闭包
输入
# ε-ΝFA -> DFA
import re # 引入正则表达式模块
# 打开文件
with open(r'.\ΝFA1.txt', encoding='utf-8') as file: # 第一例
# with open(r'.\ΝFA2.txt', encoding='utf-8') as file: # 第二例
lines = file.readlines() # 按行读取文件
# for line in lines: # 展示文件
# print(line, end='')
# 创建全局字典,为后面函数所用
e_closure = {} # 创建空状态转移字典(ε闭包)
state_closure = {} # 创建状态转移字典,用于保存原状态转移函数
# 创建每一个状态的ε闭包
def Closure(): # 定义e闭包函数
p1 = re.compile(r"[{](.*?)[}]", re.S) # 正则表达式匹配大括号中状态
# ————————————先单独处理第一行,因为带有起始符#————————————
linelist0 = lines[1].split() # 将一行解析为列表形式
# 求第一行的状态转移函数,并保存
state_closure[linelist0[0][1:3] + '0'] = linelist0[1][1:-1].split()
state_closure[linelist0[0][1:3] + '1'] = linelist0[2][1:-1].split()
trdstate = str(re.findall(p1, linelist0[3])) # third state 用于保存e转移的所有状态
if trdstate == "['']": # 如果e转移为空
e_closure[linelist0[0][1:3]] = [linelist0[0][1:3]] # 那么e闭包只包含当前状态
else:
string1 = [linelist0[0][1:3]]
for i in trdstate[2:-2].split(','):
string1.append(i)
for j in range(2, len(lines)): # 遍历当前行下面每一行的e转移
linelist01 = lines[j].split()
trdstate = str(re.findall(p1, linelist01[3])) # third state 用于保存e转移的所有状态
if trdstate == "['']": # 如果e转移为空
break
string1.append(trdstate[2:-2])
e_closure[linelist0[0][1:3]] = string1
# ————————————遍历中间行————————————
for i in range(2, len(lines) - 1):
linelist = lines[i].split() # 将一行解析为列表形式
# 求状态转移函数
state_closure[linelist[0] + '0'] = linelist[1][1:-1].split()
state_closure[linelist[0] + '1'] = linelist[2][1:-1].split()
trdstate = str(re.findall(p1, linelist[3])) # third state 用于保存e转移的所有状态
if trdstate == "['']": # 如果e转移为空
e_closure[linelist[0]] = [linelist[0]] # 那么e闭包只包含当前状态
else:
string1 = [linelist[0], trdstate[2:-2]]
for j in range(i + 1, len(lines)): # 遍历当前行下面每一行的e转移
linelist01 = lines[j].split()
trdstate = str(re.findall(p1, linelist01[3])) # third state 用于保存e转移的所有状态
if trdstate == "['']": # 如果e转移为空
break
string1.append(trdstate[2:-2])
e_closure[linelist[0]] = string1
# ————————————单独处理最后一行,因为带有终止符*————————————
i = len(lines) - 1
linelisti = lines[i].split() # 将一行解析为列表形式
# 求状态转移函数
state_closure[linelisti[0][1:3] + '0'] = linelisti[1][1:-1].split()
state_closure[linelisti[0][1:3] + '1'] = linelisti[2][1:-1].split()
trdstate = str(re.findall(p1, linelisti[3])) # third state 用于保存e转移的所有状态
if trdstate == "['']": # 如果e转移为空
e_closure[linelisti[0][1:3]] = [linelisti[0][1:3]] # 那么e闭包只包含当前状态
else:
e_closure[linelisti[0][1:3]] = [linelisti[0][1:3], trdstate[2:-2]]
return e_closure, state_closure # 返回元组,0号元素为e闭包,1号元素为状态转移字典
# 构造新状态列表
def New_state_closure():
q = [] # 创建新状态列表
# ————————————处理第一个状态————————————
q.append(e_closure['q0']) # 第一个状态设置为q0的ε闭包
l0 = [] # 创建input为0时的状态列表
l1 = [] # 创建input为1时的状态列表
for state in e_closure['q0']: # 遍历第一个新状态的子状态
for i in state_closure.keys(): # 遍历子状态转移集
if i == state + '0' and state_closure[i] != []: # 如果为当前状态,且input = '0',并排除空集
l0 += state_closure[i] # 保存状态
if i == state + '1' and state_closure[i] != []:
l1 += state_closure[i]
# 将新状态分情况保存在新状态列表
if l0 == [] and l1 != []:
q.append([])
q.append(e_closure[l1[0]])
elif l0 != [] and l1 == []:
q.append(e_closure[l0[0]])
q.append([])
elif l0 == [] and l1 == []:
q.append([])
q.append([])
else:
q.append(e_closure[l0[0]]) # 保存的为其ε闭包
q.append(e_closure[l1[0]])
# ————————————处理其余状态————————————
n = 1 # 从状态列表q中第一个元素开始遍历
chongfu = 0 # 重复判定初始为0(不重复)
while True:
l0 = [] # 创建input为0时的状态列表
l1 = [] # 创建input为1时的状态列表
if n != 1:
for i in range(1, n): # 判断前面是否有该状态
if q[n] == q[i]:
chongfu = 1 # 重复
break
else:
chongfu = 0 # 不重复
if q[n] == [] or chongfu: # 如果该状态为空集或重复
if len(q) == n + 1: # 如果列表结束
return q # ~~~~~~~~~~~~函数结束,返回新状态列表~~~~~~~~~~~~
else: # 则跳到下一状态
n += 1
else: # 继续更新新状态列表
for state in q[n]: # 遍历第n个新状态的子状态
for i in state_closure.keys(): # 遍历子状态转移集
if i == state + '0' and state_closure[i] != []: # 如果为当前状态,且input = '0',并排除空集
l0 += state_closure[i] # 保存状态
if i == state + '1' and state_closure[i] != []:
l1 += state_closure[i]
if l0 == [] and l1 != []:
q.append([])
q.append(e_closure[l1[0]])
elif l0 != [] and l1 == []:
q.append(e_closure[l0[0]])
q.append([])
elif l0 == [] and l1 == []:
q.append([])
q.append([])
else:
q.append(e_closure[l0[0]])
q.append(e_closure[l1[0]])
n += 1
# 格式化输出新状态列表
def Print_New_state(Q):
# 重命名
record = [] # 记录列表,用于保存已经重新命名的元素
n = 1
i = 1
while True:
if (f'q{n}' not in record) and (Q[i] not in record):
now = Q[i]
if now == []:
Q[i] = ''
i += 1
if i == len(Q):
break
else:
for j in range(i, len(Q)):
if Q[j] == now:
Q[j] = f'q{n}'
record.append(f'q{n}')
n += 1
i += 1
else:
i += 1
if i == len(Q):
break
for i in range(1, len(Q)): # 加括号
Q[i] = '{' + Q[i] + '}'
# 按格式输出
print('0 1 epsilon')
for i in range(1, len(Q), 2):
if i == 1:
print('#q0 %s %s' % (Q[i], Q[i + 1]))
elif i == len(Q) - 2:
print('*q%s %s %s' % (i - 3, Q[i], Q[i + 1]))
else:
print('q%s %s %s' % (i - 2, Q[i], Q[i + 1]))
if __name__ == '__main__':
closures = Closure()
# print(Closure()) # 展示e闭包和状态转移字典
Q = New_state_closure()
# print(Q) # 展示新状态列表Q
Print_New_state(Q)
经验总结:
先把所有要点都明确之后再搞,要不全是bug
先用伪代码在pycharm里写一遍
可以用思维导图解释算法流程