【直接NFA->DFA】

1.为什么要加#?

比如

(a|b)*a b b #
 1  2  3 4 5 6

因为对于每个NFA的状态集,比如{1} 表示的是分析到了1对应的位置之前。 

所以如果不加#的话, 对于{5} 表示的是分析到了b之前, 但这个时候并没有结束。

那把{1}  表示的是分析到了1对应的位置之前 改成 分析到了1对应的位置之后,

又会发现一个问题,那怎么表示start,最开始的状态呢? 可以在(a|b) * a b b之前加个 ^符号。

但是觉得还是放在#后面比较好些。


2.为什么计算followpos的时候只需要那2条规则(cat和star)?

因为对于 | 来说无法推导出follow关系
使用子集法将非确定有限自动机(NFA)确定化为确定有限自动机(DFA)是编译原理中的经典问题 。下面是一个使用 C++ 实现子集法将 NFA 确定化为 DFA 的示例代码: ```cpp #include <iostream> #include <vector> #include <set> #include <map> #include <queue> // 定义状态集合 using StateSet = std::set<int>; // 定义 NFA 转移表 using NFATable = std::map<int, std::map<char, StateSet>>; // 定义 DFA 转移表 using DFATable = std::map<StateSet, std::map<char, StateSet>>; // 计算 ε-闭包 StateSet epsilonClosure(const NFATable& nfa, const StateSet& states) { std::queue<int> q; StateSet closure = states; for (int state : states) { q.push(state); } while (!q.empty()) { int current = q.front(); q.pop(); auto it = nfa.find(current); if (it != nfa.end()) { auto epsTransitions = it->second.find('$'); if (epsTransitions != it->second.end()) { for (int nextState : epsTransitions->second) { if (closure.find(nextState) == closure.end()) { closure.insert(nextState); q.push(nextState); } } } } } return closure; } // 计算状态集合在某个输入符号下的转移 StateSet move(const NFATable& nfa, const StateSet& states, char input) { StateSet result; for (int state : states) { auto it = nfa.find(state); if (it != nfa.end()) { auto inputTransitions = it->second.find(input); if (inputTransitions != it->second.end()) { result.insert(inputTransitions->second.begin(), inputTransitions->second.end()); } } } return result; } // 使用子集法将 NFA 转换为 DFA DFATable nfaToDfa(const NFATable& nfa, const std::vector<char>& inputs) { DFATable dfa; std::queue<StateSet> unmarked; // 初始状态的 ε-闭包 StateSet startState = epsilonClosure(nfa, {0}); unmarked.push(startState); dfa[startState]; while (!unmarked.empty()) { StateSet current = unmarked.front(); unmarked.pop(); for (char input : inputs) { if (input == '$') continue; StateSet next = epsilonClosure(nfa, move(nfa, current, input)); if (!next.empty()) { dfa[current][input] = next; if (dfa.find(next) == dfa.end()) { unmarked.push(next); dfa[next]; } } } } return dfa; } // 打印 DFA 转移表 void printDfa(const DFATable& dfa, const std::vector<char>& inputs) { std::cout << "DFA Transition Table:" << std::endl; for (const auto& entry : dfa) { const StateSet& from = entry.first; std::cout << "State: {"; for (int state : from) { std::cout << state << " "; } std::cout << "}" << std::endl; for (char input : inputs) { if (input == '$') continue; auto it = entry.second.find(input); if (it != entry.second.end()) { const StateSet& to = it->second; std::cout << " " << input << " -> {"; for (int state : to) { std::cout << state << " "; } std::cout << "}" << std::endl; } } } } int main() { // 示例 NFA 转移表 NFATable nfa = { {0, {{'a', {1}}, {'$', {2}}}}, {1, {{'b', {2}}}}, {2, {}} }; // 输入符号集合 std::vector<char> inputs = {'a', 'b', '$'}; // 将 NFA 转换为 DFA DFATable dfa = nfaToDfa(nfa, inputs); // 打印 DFA 转移表 printDfa(dfa, inputs); return 0; } ``` ### 代码解释 1. **状态集合的表示**:使用 `std::set<int>` 来表示状态集合。 2. **NFA 转移表**:使用 `std::map<int, std::map<char, StateSet>>` 来表示 NFA 的转移表。 3. **ε-闭包计算**:`epsilonClosure` 函数用于计算一个状态集合的 ε-闭包。 4. **状态转移计算**:`move` 函数用于计算一个状态集合在某个输入符号下的转移。 5. **子集法转换**:`nfaToDfa` 函数使用子集法将 NFA 转换为 DFA。 6. **打印 DFA**:`printDfa` 函数用于打印 DFA 的转移表。 ### 复杂度分析 - **时间复杂度**:$O(2^n * m)$,其中 $n$ 是 NFA 的状态数,$m$ 是输入符号的数量。 - **空间复杂度**:$O(2^n * m)$,主要用于存储 DFA 的转移表。 ### 注意事项 - 代码中的 `$` 表示 ε 转移。 - 示例中的 NFA 转移表可以根据实际情况进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值