編譯原理:NFA轉DFA(含資料視覺化)
阿新 • • 發佈:2021-09-28
def printlist(l): for i in range(len(l)): print(l[i], end=" ") print("----------------------------輸入NFA樣例-----------------------------") ab = eval(input("請輸入變數的個數")) print("請輸入變數名稱(用_(下劃線)表示空)") aabb = [] for i in range(1, ab + 1): aabb_eval = input("第" + str(i) + "個變數的名稱是: ") aabb.append(aabb_eval) printlist(aabb) # [a,b,c] # 輸入變數的個數之後將為這個創造字典 l = [{} for i in range(ab)] # 建立和變數相同個數的字典 n = 0 while n < ab: print("開始構造變數" + aabb[n] + "的兩節點狀態") while True: status = input("請輸入起始狀態") end_status = input("請輸入終止狀態") if status != '#' or end_status != '#': l[n].setdefault(status, end_status) else: print(aabb[n] + "變數的構造輸入已經結束") break n = n + 1 for i in range(len(l)): if aabb[i] == '_': print("空變數的節點起始關係為:" + str(l[i])) else: print("變數" + aabb[i] + "的節點起始關係為:" + str(l[i])) print(l) # 空變數的節點起始關係為:{'2': '3', '1': '4', '5': '6'} # 變數a的節點起始關係為:{'1': '4', '3': '5'} # 變數b的節點起始關係為:{'5': '2', '3': '5'} key_list = [] for i in range(len(l)): for k in l[i].keys(): if k not in key_list: key_list.append(k) print("狀態節點有:", end=" ") # {1,2,3,4,5} printlist(key_list) print() start = input('請輸入起始節點') end_list = [] a = "" while a != "#": a = input("請輸入終止節點(集),以#表示結束") end_list.append(a) end_list.pop() print("起始節點是:" + start) print("終止節點(集)是:", end="") printlist(end_list) # 變數a的節點起始關係為:{'1': '2', '3': '4'} # 變數b的節點起始關係為:{'1': '3', '5': '2'} # 空變數的節點起始關係為:{'2': '3', '4': '5'} # 狀態節點有: 1 3 5 2 4 # 請輸入起始節點1 # 請輸入終止節點(集),以#表示結束3 # 請輸入終止節點(集),以#表示結束# # 起始節點是:1 # 終止節點(集)是:3 print() print("\n-------------------將狀態節點儲存到檔案中-----------------") with open('nfa.txt', 'w') as f: f.write(start + "\n") for i in range(len(end_list)): f.write(end_list[i] + " ") f.write("\n") for j in range(len(l)): # j表示第幾個字典 for k in range(len(l[j])): # k表示第幾個鍵值對 for m in l[j].keys(): # m表示第幾個鍵 f.write(m + " " + aabb[j] + " " + l[j][m] + "\n") print("\n------------------讀取檔案中的資訊----------------------") with open('nfa.txt', 'r') as r: nfa = [] for line in r.readlines(): # 將檔案資料內容儲存到nfa列表當中 line_rstrip = line.rstrip('\n') nfa.append(line_rstrip) # print(nfa) begin_start = nfa[0].split() # 起始節點 #print(begin_start) end_end_list = nfa[1].split() # 終止節點 #print(end_end_list) # 如果是按照前面的方法建立的,那麼以上程式碼沒有必要,直接用start和end_list即可 trans_nfa = nfa[2:] #print(trans_nfa) for i in range(len(trans_nfa)): trans_nfa[i] = trans_nfa[i].split() #print(trans_nfa) # #[['1', 'a', '2'], ['3', 'a', '4'], ['1', 'a', '2'], ['3', 'a', '4'], ['1', 'b', '2'], ['3', 'b', # '4'], ['1', 'b', '2'], ['3', 'b', '4'], ['1', '_', '2']] 所有的狀態已經標識好了 state_to_draw = [] # 狀態節點 para_to_draw = [] # 轉換變數 for i in range(len(trans_nfa)): state_to_draw.append(trans_nfa[i][0]) state_to_draw.append(trans_nfa[i][2]) para_to_draw.append(trans_nfa[i][1]) # print(state_to_draw) # print(para_to_draw) state0 = list(set(state_to_draw)) # 去除節點重複 state0.sort(key=state_to_draw.index) # 對節點進行排序 para0 = list(set(para_to_draw)) para0.sort(key=para_to_draw.index) # print(state0) # ['0', '1', '2', '4', '3', '6', '5', '7', '8', '9', '10'] # print(para0) # ['_', 'a', 'b'] if '_' in para0: para0.remove('_') # 去掉空 _closure = dict() # 表示空串可以到達的集合 print("\n--------------開始作圖-------------------") from graphviz import Digraph def draw_nfa(): g = Digraph('G', filename='nfa.gv', format='png') for i in range(len(trans_nfa)): g.edge(trans_nfa[i][0], trans_nfa[i][2], label=trans_nfa[i][1]) for i in range(len(begin_start)): g.node(begin_start[i], color='red') for i in range(len(end_end_list)): g.node(end_end_list[i], shape='doublecircle') g.view() draw_nfa() print("\n------------nfa作圖完畢------------------") print("\n-----------開始進行NFA轉DFA---------------") ## 尋找所有空閉包 for i in range(len(state0)): res = [state0[i]] # 第i個節點 # print(res) for j in range(len(trans_nfa)): if trans_nfa[j][0] == state0[i] and trans_nfa[j][1] == '_': # 如果目前研究的節點裡面存在著空 res.extend(trans_nfa[j][2]) # 這裡用 _closure[state0[i]] = list(set(res)) # 到此,一個狀態所有的空閉包都會顯現出來,接下來只要一查到底即可 # print(_closure) # {'0': ['1', '0', '7'], '1': ['1', '2', '4'], '2': ['2'], '4': ['4'], '3': ['6', '3'], '6': ['7', '6', '1'], '5': ['5', '6'], '7': ['7'], '8': ['8'], '9': ['9'], '10': ['10']} # 空閉包的遞迴查詢------ def find_closure(state_input): state_now = _closure[state_input] # 查詢輸入一個狀態下是否有空閉包 ['1', '0', '7'] state_now_list = [] for state_now_para in state_now: state_now_list = state_now_list + _closure[state_now_para] # 遞迴查詢 state_now_list = list(set(state_now_list)) ## 嘗試輸出 #print(state_now_list) # ['0', '7', '1', '2', '4'] while set(state_now) != set(state_now_list): # 多次查詢 state_now = state_now_list state_now_list = [] for state_now_para in state_now: state_now_list = state_now_list + _closure[state_now_para] state_now_list = list(set(state_now_list)) return state_now_list A = find_closure(state0[0]) # 初始狀態的空閉包 #print(A) # ['1', '7', '4', '2', '0'] def find_state(l_state): res = dict() # 建立一個字典,裡面的值是狀態集合 for c in para0: # ['_', 'a', 'b'] res_two = [] for i in range(len(l_state)): for j in range( len(trans_nfa)): # [['0', '_', '1'], ['1', '_', '2'], ['1', '_', '4'], ['2', 'a', '3'], ['3', '_', '6'], ['4', 'b', '5'], ['5', '_', '6'], ['6', '_', '7'], ['7', 'a', '8'], ['8', 'b', '9'], ['9', 'b', '10'], ['6', '_', '1'], ['0', '_', '7']] if trans_nfa[j][0] == l_state[i] and trans_nfa[j][1] == c: res_two.append(trans_nfa[j][2]) result = [] for k in res_two: result = result + find_closure(k) res[c] = list(set(result)) return res number = 0 length = 1 state_list = [] state_list.append(A) # [['0', '7', '1', '2', '4']] while number < length: A2 = find_state(state_list[number]) number = number + 1 for c in para0: temp = 1 for p in range(length): if set(A2[c]) == set(state_list[p]): temp = 0 if temp == 1: state_list.append(A2[c]) length = length + 1 #print(state_list) # [['0', '2', '4', '1', '7'], # ['2', '3', '6', '4', '8', '1', '7'], # ['2', '6', '4', '5', '1', '7'], # ['9', '2', '6', '4', '5', '1', '7'], # ['2', '6', '4', '10', '5', '1', '7']] #獲取開始節點和結束節點 dfa_begin = [] dfa_end = [] for i in range(len(begin_start)): # 檢視是否存在空……變數 dfa_begin.append(find_closure(begin_start[i])) for j in range(len(end_end_list)): for k in range(len(state_list)): if end_end_list[j] in state_list[k]: #如果nfa的結束節點是在我的某一個狀態列表裡面 if state_list[k] not in dfa_end: dfa_end.append(state_list[k]) print(dfa_begin) print(dfa_end) while [] in state_list: state_list.remove([]) print('DFA狀態表: ', state_list) print("DFA起始狀態: ", dfa_begin) print("DFA終止狀態:", dfa_end) # DFA狀態表為: [['4', '2', '0', '1', '7'], ['4', '2', '1', '7', '8', '3', '6'], ['4', '2', '1', '7', '6', '5'], ['4', '2', '1', '7', '9', '6', '5'], ['4', '2', '1', '7', '10', '6', '5']] # DFA開始狀態: [['4', '2', '0', '1', '7']] # DFA終止狀態: [['4', '2', '1', '7', '10', '6', '5']] def draw_dfa(state_list, begin, end): g = Digraph('G', filename='dfa.gv', format='png') begin_aaa = [] end_aaa = [] for i in range(len(begin)): begin_aaa.append(" ".join(sorted(begin[i]))) for j in range(len(end)): end_aaa.append(" ".join(sorted(end[j]))) for i in range(len(state_list)): dicttttt = find_state(state_list[i]) for j in para0: if state_list[i] != [] and dicttttt[j] != []: g.edge(" ".join(sorted(state_list[i])), " ".join(sorted(dicttttt[j])), label=j) for k in range(len(begin_aaa)): g.node(begin_aaa[k], color='red', shape='circle') for i in range(len(state_list)): g.node(" ".join(sorted(state_list[i])), color='blue', shape='circle') for j in range(len(end_aaa)): if end_aaa[j]!=begin_aaa[0]: g.node(end_aaa[j], shape='doublecircle') else: g.node(end_aaa[j], shape='doublecircle',color='red') g.view() draw_dfa(state_list, dfa_begin, dfa_end) state_dfa_other_name=[ chr(65+i) for i in range(len(state_list))] #['A', 'B', 'C', 'D', 'E'] start_char=state_dfa_other_name[ state_list.index(dfa_begin[0])] start_char=list(start_char) print(start_char) end_char=[] for i in range(len(dfa_end)): s=state_dfa_other_name[state_list.index(dfa_end[i])] end_char.append(s) print(end_char) # def draw_dfa_2(state_list,state_dfa_other_name, start_char, end_char): # g = Digraph('G', filename='dfa.gv', format='png') # # begin_aaa = [] # # end_aaa = [] # # for i in range(len(begin)): # # begin_aaa.append(" ".join(sorted(begin[i]))) # # for j in range(len(end)): # # end_aaa.append(" ".join(sorted(end[j]))) # # for i in range(len(state_list)): # dicttttt = find_state(state_list[i]) # for j in para0: # if state_list[i] != [] and dicttttt[j] != []: # g.edge(" ".join(sorted(state_list[i])), " ".join(sorted(dicttttt[j])), label=j) # for k in range(len(start_char)): # g.node(start_char[k], color='red', shape='circle') # for i in range(len(state_list)): # g.node(state_dfa_other_name[i], color='blue', shape='circle') # for j in range(len(end_char)): # g.node(end_char[j], shape='doublecircle') # g.view() # draw_dfa_2(state_list,state_dfa_other_name,start_char,end_char) # def min_list(state_list,dfa_end): # l=state_list.remove(dfa_end) # min_dfa_column_one=[] # for i in range(len(state_list)): # if find_state(state_list[i]) == dfa_end: # min_dfa.append(state_list[i])
本文來自部落格園,作者:{Zeker62},轉載請註明原文連結:https://www.cnblogs.com/Zeker62/p/15350095.html