算法:从NFA构造DFA(子集法)
参考代码一:
输入: 一个NFA N
输出 : 一个接受同一正规集的DFA D
# 构造NFA
class NFA:
# 初始化NFA
def __init__(self, S, s0, F, move):
self.S = S # 状态集(list)
self.s0 = s0 # 初态(int)
self.F = F # 终态(int)
self.move = move # 状态转换函数(list套dict)
# 计算状态集T的n(代替ε)闭包U
def getClosure(self, T):
U = list() # 闭包集合
Stack = list() # 栈
for t in T:
Stack.append(t) # 将t入栈
U.append(t) # 先将T加入U
# 当栈非空
while Stack:
t = Stack.pop() # 取出栈顶元素
# 如果能转换(判断字典中是否存在key为'n')
if 'n' in move[t]:
u = self.move[t]['n'] # 得到转换后状态u
# 若转换后状态不在闭包集合U中,加u入U
if u not in U:
# 因为u为list类型,所以循环加入
for x in u:
Stack.append(x)
U.append(x)
# 如果不能转换
else:
#print('不能转换,啥事都不干~')
pass
#print('返回闭包', U)
return U
# smove方法,T为初态集,n为待识别字符(str类型),返回转换后的状态集U
def smove(self, T, n):
U = list() # 存储smove后的状态集
for t in T:
# 如果能转换(判断字典中是否存在key为'n')
if n in move[t]:
u = self.move[t][n] # 得到转换后状态u
# 若转换后状态不在闭包集合U中,加u入U
if u not in U:
# 因为u为list类型,所以循环加入
for x in u:
U.append(x)
# 如果不能转换
else:
#print('不能转换,啥事都不干~')
pass
return U
# 构造DFA
class DFA:
# 通过NFA对象N构造DFA
def __init__(self, N):
print('---------开始使用子集法构造DFA---------')
self.s0 = N.getClosure([0]) # 初态(list)
self.Dstates = [self.s0] # 存储DFA的状态
self.DstatesFlag = [0] # 记录状态是否被标记过,元素个数代表还未被标记的数目
self.F=N.F#终态
curIndex = 0 # 当前处理到的Dstates的下标
Dtran = list() # 状态转换矩阵
U1 = list()#暂存器,用于存储转换后的状态集,便于写入转换矩阵
U2 = list()#同上
# 当DFA状态集中有尚未标记的状态T
while self.DstatesFlag:
self.DstatesFlag.pop() # 取出一个标记
#循环求闭包
for ch in ['a', 'b']:
#求出smove后的闭包U
U = N.getClosure(N.smove(self.Dstates[curIndex], ch))
#条件判断构造写入格式Dtran.append({'a': U1, 'b': U2})
if ch == 'a':
U1 = U
else:
U2 = U
# 如果U不在Dstates中,将U作为未标记的状态加入Dstates中
if U not in self.Dstates:
self.Dstates.append(U)#将U加入到状态集中
self.DstatesFlag.append(0)#长度增1,表示新增一个未标记状态
#print('Dstates更新为:',self.Dstates)
Dtran.append({'a': U1, 'b': U2})#将转换结果写入转换矩阵中
curIndex+=1 # 下标增1
self.move = Dtran # 构造状态转换函数(list套dict)
print('DFA的初态s0:',self.s0)
print('DFA的终态F:', self.F)
print('DFA的状态集Dstates:', self.Dstates)
print('DFA的状态转换矩阵Dtran:', self.move)
print('---------DFA构造完成,开始验证字符识别功能---------')
# 判断是否接受x
def isAccept(self, x):
print('开始判断是否接受输入的字符串:',x)
#循环识别输入字符串
for ch in x:
#因为Dstatea中的状态为顺序加入,A集合对象下标0,B对应下标1
# 而move矩阵也是按此方式存储,得到当前状态集在Dstates中的下标
curindex=self.Dstates.index(self.s0)
#状态转换
if ch not in ['a', 'b']:
break
self.s0=self.move[curindex][ch]
print('状态转换一次,此时的状态集为:', self.s0)
#如果转换后状态集的下标等于Dstates的长度-1
#说明当前转换状态为Dstates的末尾状态,即终态
if self.F in self.s0:
print('识别已结束,字符串',x,'被接受~~')
else:
print('识别已结束,字符串',x,'被拒绝T T')
return 0
if __name__ == '__main__':
print("---------本程序用于识别正规式为'(a|b)*abb'的字符序列---------")
print("---------即将开始收集用于构造NFA的初始数据,请按提示操作---------' ")
# 构造NFA 开始
#S = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("请输入状态集S,输入格式为List嵌套Dict,如'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]' ")
S = eval(input(":"))
# s0 = 0
s0 = int(input("请输入初态s0,如'0' :"))
# F = 10
F = int(input("请输入终态F,如'10' :"))
#move = [{'n': [1, 7]}, {'n': [2, 4]}, {'a': [3]}, {'n': [6], }, {'b': [5]}, {'n': [6]}, {'n': [1, 7]}, {'a': [8]}, {'b': [9]}, {'b': [10]},{}]
print("请输入状态转移矩阵,输入格式为List嵌套Dict,如'[{'n': [1, 7]}, {'n': [2, 4]}, {'a': [3]}, {'n': [6], }, {'b': [5]}, {'n': [6]}, {'n': [1, 7]}, {'a': [8]}, {'b': [9]}, {'b': [10]},{}]' ")
move = eval(input(":"))
N = NFA(S, s0, F, move)
print("---------数据收集完毕,NFA构造完成---------' ")
# 构造NFA 结束
D=DFA(N)#通过NFA对象N构造DFA
#print(D.move)#输出DFA转换矩阵
while True:
x = input('请输入要识别的字符串x:')#提示输入
if x=='quit':
print('程序结束运行')
break
D.isAccept(x) # 判断是否接受
测试样例:
请输入状态集S,输入格式为List嵌套Dict:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
请输入初态s0 :
0
请输入终态F :
10
请输入状态转移矩阵,输入格式为List嵌套Dict:
[{‘n’: [1, 7]}, {‘n’: [2, 4]}, {‘a’: [3]}, {‘n’: [6], }, {‘b’: [5]}, {‘n’: [6]}, {‘n’: [1, 7]}, {‘a’: [8]}, {‘b’: [9]}, {‘b’: [10]},{}]’
参考代码二:
1.通过输入NFA开始状态,结束状态,输入状态个数,状态机权值个数(字母个数),还有映射关系,来确定NFA5元组,通过输入转换表,确定了映射关系,字母集,有穷状态集。
2.编写代码实现e-closure闭包即代码中Empty_Closure(string)。
3.编写代码实现I操作,即状态通过字母集中某一状态所能达到的所有状态,通过递归实现(导致代码比较长,如果输入超过6个状态,6个字母集会导致时间较长)。
4.将计算出来的结果保存至DFA 状态矩阵中。
__author__ = 'PythonStriker'
global NFA_StautsMatrix, DFA_StautsMatrix, StartWorld, EndWorld, \
StatusNumber, EnterNumber, EnterWorld, NFA_StatusWorld, DFA_StatusWrold
EnterWorld = [] # 输入状态
NFA_StatusWorld = [] # NFA有穷状态集
DFA_StatusWrold = [] # DFA有穷状态集
def main():
EndList = []
global NFA_StautsMatrix, DFA_StautsMatrix, StartWorld, EndWorld, \
StatusNumber, EnterNumber, EnterWorld, NFA_StatusWorld, DFA_StatusWrold
StartWorld = input("输入开始状态:")
EndWorld = input("输入结束状态:")
StatusNumber = int(input("输入状态个数:"))
EnterNumber = int(input("状态机输入个数:"))
print("输入不确定有穷状态机转换表:")
NFA_StautsMatrix = [[] for _ in range(0, StatusNumber + 1)] # NFA状态转换表
for row in range(0, StatusNumber + 1): # 存入状态转换表
line = input().split(' ')
for column in range(len(line)):
NFA_StautsMatrix[row].append(line[column])
for enter in NFA_StautsMatrix[0]: # 存入输入状态
if enter != '\\' and enter != '&':
EnterWorld.append(enter)
for row in range(1, StatusNumber + 1): # NFA有穷状态集
NFA_StatusWorld.append(NFA_StautsMatrix[row][0])
DFA_Start = Empty_Closure(StartWorld) # DFA开始状态
for status in DFA_StatusWrold:
for enter in EnterWorld:
Empty_Closure(Enter_Closure(status, enter))
DFA_StautsMatrix = [[] for _ in range(0, len(DFA_StatusWrold) + 1)]
for row in range(0, len(DFA_StatusWrold) + 1):
if row == 0:
line = "\ a b c"
line = line.split(' ')
for column in range(len(line)):
DFA_StautsMatrix[row].append(line[column])
else:
if row <= len(DFA_StatusWrold):
number = DFA_StatusWrold[row - 1]
lineList = []
line = number
for enter in EnterWorld:
if Empty_Closure(Enter_Closure(number, enter)) == False:
line = line + ' ' + '&'
else:
line = line + ' ' + Empty_Closure(Enter_Closure(number, enter))
lineList = line.split(' ')
for column in range(len(lineList)):
DFA_StautsMatrix[row].append(lineList[column])
print("------------------------------DFA-------------------------------------")
print("确定有穷自动机DFA_S:", end='')
for number in DFA_StatusWrold:
print(number, end=' ')
print("\n确定有穷自动机DFA_∑:", end='')
for number in EnterWorld:
print(number, end=' ')
print("\n确定有穷自动机DFA_S0:" + DFA_Start)
for number in DFA_StatusWrold:
if EndWorld in number:
EndList.append(number)
print("确定有穷自动机DFA_Z:", end='')
for number in EndList:
print(number, end=' ')
print("\n确定有穷自动机DFA_δ:")
for row in DFA_StautsMatrix:
print()
for column in row:
print('%8s' % column, end='')
def Empty_Closure(string):
global NFA_StautsMatrix, DFA_StautsMatrix, StartWorld, EndWorld, \
StatusNumber, EnterNumber, EnterWorld, NFA_StatusWorld, DFA_StatusWrold
List = []
flag = 0
NewList = []
NewStatus = string
if string == False:
return False
if ',' not in string:
while flag == 0:
if ',' not in string:
row = NFA_StatusWorld.index(string) + 1
if NFA_StautsMatrix[row][1] != '&' and NFA_StautsMatrix[row][1] != '*':
if NFA_StautsMatrix[row][1] not in NewStatus:
NewStatus = NewStatus + ',' + NFA_StautsMatrix[row][1]
string = NFA_StautsMatrix[row][1]
else:
flag = 1
else:
flag = 1
else:
List = string.split(',')
for number in range(len(List)):
if List[number] not in NewStatus:
NewStatus = NewStatus + ',' + List[number]
string = List[number]
elif List[number] in NewStatus and List[number] in NewStatus:
flag = 1
break
if ',' in NewStatus:
NewList = NewStatus.split(',')
NewList = set(NewList)
NewList = (sorted(set(NewList)))
NewStatus = ','.join(NewList)
if NewStatus not in DFA_StatusWrold:
DFA_StatusWrold.append(NewStatus)
return NewStatus
else:
List = string.split(',')
for number in List:
row = NFA_StatusWorld.index(number) + 1
if ',' not in NFA_StautsMatrix[row][1]:
if NFA_StautsMatrix[row][1] != '&' and NFA_StautsMatrix[row][1] != '*':
if NFA_StautsMatrix[row][1] not in NewStatus:
NewStatus = NewStatus + ',' + NFA_StautsMatrix[row][1]
else:
pass
else:
break
if ',' in NewStatus:
NewList = NewStatus.split(',')
NewList = set(NewList)
NewList = (sorted(set(NewList)))
NewStatus = ','.join(NewList)
if NewStatus not in DFA_StatusWrold:
DFA_StatusWrold.append(NewStatus)
return NewStatus
def Enter_Closure(string, enter):
global NFA_StautsMatrix, DFA_StautsMatrix, StartWorld, EndWorld, \
StatusNumber, EnterNumber, EnterWorld, NFA_StatusWorld, DFA_StatusWrold
status = '99999'
List = []
NewList = []
if ',' not in string:
row = NFA_StatusWorld.index(string) + 1
if NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '&' \
and NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '*' \
and string != NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]:
if status == '99999':
status = NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
status = status + ',' + NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
elif NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '&' \
and NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '*' \
and string == NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]:
if string in status:
pass
else:
if status == '99999':
status = NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
status = status + ',' + NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
return False
if status != '99999':
if string not in status:
if Enter_Closure(status, enter):
status = status + ',' + Enter_Closure(status, enter)
return status
else:
return False
else:
List = string.split(',')
for number in List:
row = NFA_StatusWorld.index(number) + 1
if NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '&' \
and NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '*' \
and number != NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]:
if status == '99999':
status = NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
status = status + ',' + NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
elif NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '&' \
and NFA_StautsMatrix[row][EnterWorld.index(enter) + 2] != '*' \
and number == NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]:
if number in status:
break
else:
if status == '99999':
status = NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
status = status + ',' + NFA_StautsMatrix[row][EnterWorld.index(enter) + 2]
else:
pass
if status != '99999':
NewList = status.split(',')
for number in NewList:
if number not in List:
if Enter_Closure(number, enter):
status = status + ',' + Enter_Closure(number, enter)
return status
else:
return False
if __name__ == "__main__":
main()
测试样例:
输入开始状态:1
输入结束状态:3
输入状态个数:3
状态机输入个数:4
输入不确定有穷状态机转换表:
\ & a b c
1 1,3 & 2 3
2 & 1 3 1,2
3 & & & &