从NFA构造DFA(自动机)

算法:从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

参考代码二:

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 & & & &

图2

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南有芙蕖

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值