编译技术:正规式、NFA、DFA、最简DFA的转换

正规式、NFA、DFA、最简DFA的转换

在编译原理中,正规式、NFA(非确定有穷自动机)、DFA、最简DFA的转换在词法分析中是十分重要的一个环节。

  • 一般来说:我们经常碰到的问题类型都是如下类型的:
    正规式->NFA->DFA->最简DFA。
  • 对于这类问题我们可以经过以下三个步骤进行解决:
    (1)正规式->NFA(三个替换规则);
    (2)NFA->DFA (子集构造法);
    (3)DFA->最简DFA(分割法)。

知识点储备

三个替换规则

(正规式R到NFA的转化)
在这里插入图片描述

子集构造法

  • 预备知识
    (1 )状态集的ε-闭包:状态集I中的==任何状态s经任意条ε弧能到达的所有状态的集合,定义为状态集I的ε -闭包,表示为ε -closure()。

(2)状态集的a弧转换: 状态集I中的任何状态s经过一条a弧而能到达的所有状态的集合,定义为状态集I的a弧转换,表示为move(l,a)。

(3)状态集的a弧转换的闭包: la= ε-closure(move(l,a))。

  • 子集构造法求DFA的步骤

对于输入字符集合∑={a1,a2…ak},我们构造一张k+1列的表格(行数未做限制)。一般来来讲,步骤如下:
(1)表格的第一行第一列的位置写的是从NFA的起始节点经过任意个ε所能到达的结点集合S0的ε-closure(S0)。
(2)接着填写该行剩余位置的信息,做法是在对应的位置上填写la= ε-closure(move(l,a))。Ia表示从该集合开始经过一个a所能到达的集合,经过一个a的意思是可以略过前后的ε。
(3)检查该行上的所有状态子集,如果未在第一列出现,则将该状态子集写到第一列。
(4)重复(2)(3)的步骤,直到所有状态子集均在第一列上出现即可。
(5)然后给状态子集重新编号,需要注意的是,包含原来终态的状态子集为新的终态,按照对应的转换函数f,构造对应的DFA即可。

分割法

  • 预备知识
    (1)无关状态
    ①多余状态:对于一个状态Si ,若从开始状态出发,不可能到达该状态Si,则Si为多余(无用)状态。
    ②死状态:对于一个状态Si,对任意输入符号a,若转到它本身后,不可能从它到达终止状态,则称为Si为死状态。S2为死状态。多余状态和死状态又称为无关状态。
    (2)等价状态:若Si为自动机的一个状态,我们把从Si出发能导出的所有符号串集合记为L(Si)。设有两个状态Si和Sj,若有L(Si)=L(Sj),则称Si和Sj是等价状态。
    在这里插入图片描述
    (3)可区别状态:Si,Sj不是等价状态即为可区别状态。一般有两种情况:
    ①终止状态和非终止状态是可区别状态。
    ②状态Si,Sj对于∀a∈∑,必须转到等价的状态里面,否则称其实可区别的。

  • 分割法求最简DFA的步骤

(1)首先将DFA的状态集进行初始划分,分成π=(S-Z,Z)。【其中Z为终态集合,S-Z为非终态,终态对于非终态是可以区分的】
(2)用下面的过程对π构造新的划分π new, 对π中每个组G,满足以下条件:
① 任意两个状态Si和Sj在同一组中
② move(Si, a) 和move(Sj, a) 是到不同的组中
则说明Si和Sj是可区别的,可进行划分,在π new中用刚完成的对G的划分代替原来的G, 否则不可以进行划分。
(3)重复执行(2)的操作,直到π中每个状态集都不能再进一步划分为止。
(4)合并等价状态,在每个G中,取任意状态作为代表,删去其它状态。将删去的状态关系全部转到代表状态。
(5)删去无关状态,包括从其它状态到无关状态的转换弧都都删掉。

例题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 14
    点赞
  • 121
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用C++编写的NFA转换DFA代码示例: ``` #include <iostream> #include <vector> #include <set> #include <map> using namespace std; // 定义NFA结构体 struct NFA { int start_state; // 起始状态 vector<int> accept_states; // 接受状态 map<pair<int, char>, vector<int>> transitions; // 转换函数 }; // 定义DFA结构体 struct DFA { set<int> states; // 状态集合 int start_state; // 起始状态 set<int> accept_states; // 接受状态集合 map<pair<int, char>, int> transitions; // 转换函数 }; // 获取NFA中从state状态出发通过symbol转换可以到达的所有状态 vector<int> get_next_states(NFA nfa, int state, char symbol) { vector<int> next_states; if (nfa.transitions.count(make_pair(state, symbol))) { next_states = nfa.transitions[make_pair(state, symbol)]; } return next_states; } // 获取NFA中从state状态出发可以到达的所有状态 set<int> epsilon_closure(NFA nfa, int state) { set<int> closure; closure.insert(state); bool changed = true; while (changed) { changed = false; for (int s : closure) { vector<int> next_states = get_next_states(nfa, s, 'e'); for (int next_state : next_states) { if (closure.count(next_state) == 0) { closure.insert(next_state); changed = true; } } } } return closure; } // 将NFA转换DFA DFA nfa_to_dfa(NFA nfa) { DFA dfa; // 计算NFA的epsilon闭包 set<int> start_state = epsilon_closure(nfa, nfa.start_state); dfa.states.insert(1); dfa.start_state = 1; if (nfa.accept_states.count(nfa.start_state)) { dfa.accept_states.insert(1); } map<set<int>, int> dfa_state_map; dfa_state_map[start_state] = 1; int curr_dfa_state = 1; set<int> unmarked_dfa_states; unmarked_dfa_states.insert(1); while (!unmarked_dfa_states.empty()) { int dfa_state = *unmarked_dfa_states.begin(); unmarked_dfa_states.erase(unmarked_dfa_states.begin()); set<int> nfa_states = dfa_state_map.inverse[dfa_state]; for (char symbol = 'a'; symbol <= 'z'; symbol++) { set<int> next_states; for (int nfa_state : nfa_states) { set<int> next_nfa_states = epsilon_closure(nfa, nfa_state); for (int next_nfa_state : next_nfa_states) { vector<int> transitions = get_next_states(nfa, next_nfa_state, symbol); for (int transition : transitions) { next_states.insert(transition); } } } if (!next_states.empty()) { int next_dfa_state; if (dfa_state_map.count(next_states)) { next_dfa_state = dfa_state_map[next_states]; } else { curr_dfa_state++; dfa.states.insert(curr_dfa_state); next_dfa_state = curr_dfa_state; dfa_state_map[next_states] = next_dfa_state; if (nfa.accept_states.count(next_states)) { dfa.accept_states.insert(next_dfa_state); } unmarked_dfa_states.insert(next_dfa_state); } dfa.transitions[make_pair(dfa_state, symbol)] = next_dfa_state; } } } return dfa; } int main() { // 定义NFA NFA nfa; nfa.start_state = 0; nfa.accept_states = {2}; nfa.transitions[make_pair(0, 'a')] = {1}; nfa.transitions[make_pair(1, 'b')] = {2}; nfa.transitions[make_pair(0, 'e')] = {3}; nfa.transitions[make_pair(3, 'a')] = {4}; nfa.transitions[make_pair(4, 'b')] = {2}; // 将NFA转换DFA DFA dfa = nfa_to_dfa(nfa); // 输出DFA cout << "DFA states: "; for (int state : dfa.states) { cout << state << " "; } cout << endl; cout << "DFA start state: " << dfa.start_state << endl; cout << "DFA accept states: "; for (int state : dfa.accept_states) { cout << state << " "; } cout << endl; cout << "DFA transitions: " << endl; for (auto it : dfa.transitions) { cout << " " << it.first.first << " --" << it.first.second << "--> " << it.second << endl; } return 0; } ``` 该代码使用了C++ STL库中的容器类型,如vector、set和map等,以便更方便地实现算法逻辑。在主函数中,我们先定义了一个NFA,然后调用nfa_to_dfa函数将其转换DFA,并输出DFA的各项属性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值