#include <iostream>
#include <stdio.h>
#include <cctype>
#include <stack>
#include <string>
#include <map>
#include <set>
#include <vector>
#include<iterator>
#include <fstream>
using namespace std;
/*构造NFA和DFA所需要的结构体*/
//NFA的节点
struct node
{
string nodeName;
};
//NFA的边
struct edge
{
node startName; //起始点
node endName; //目标点
char tranSymbol; //转换符号
};
//NFA的组成单元,一个大的NFA单元可以是由很多小单元通过规则拼接起来
struct elem
{
int edgeCount; //边数
edge edgeSet[100]; //该NFA拥有的边
node startName; //开始状态
node endName; //结束状态
};
// 定义 DFA 的状态
struct DFAState {
set<string> nfaStates; //一个包含NFA状态的集合
string stateName;
};
// 定义 DFA 的转换关系
struct DFATransition {
DFAState fromState;
DFAState toState;
char transitionSymbol;
};
int nodeNum = 0;
/*下面是转换为DFA的主要函数*/
// 计算 NFA 状态的ε闭包
DFAState eClosure(const set<string>& nfaStates,elem nfa) {
DFAState eClosureState;//存储计算出的ε闭包状态及其包含的NFA状态集合
eClosureState.nfaStates = nfaStates;
stack<string> stateStack;
// 初始化栈,将初始状态加入栈,最开始nfaState里只有NFA_Elem.startName
for (const string& nfaState_name : nfaStates) {
stateStack.push(nfaState_name);
}
while (!stateStack.empty()) {
string currentState = stateStack.top();
stateStack.pop();
// 遍历 NFA 的边
for (int i = 0; i < nfa.edgeCount; i++) {
edge currentEdge = nfa.edgeSet[i];
// 如果边的起始状态是当前状态,并且边的转换符号是#,那么将目标状态加入ε闭包
if (currentEdge.startName.nodeName == currentState && currentEdge.tranSymbol == '#') {
// 检查目标状态是否已经在ε闭包中,避免重复添加
if (eClosureState.nfaStates.find(currentEdge.endName.nodeName) == eClosureState.nfaStates.end()) {
eClosureState.nfaStates.insert(currentEdge.endName.nodeName);
// 将目标状态加入栈以便进一步处理
stateStack.push(currentEdge.endName.nodeName);
}
}
}
}
// 为ε闭包分配一个唯一的名称
for (const string& nfaState_name : eClosureState.nfaStates) {
eClosureState.stateName += nfaState_name;
}
return eClosureState;
}
//move函数
DFAState move(const DFAState& dfaState, char transitionSymbol,elem nfa) {
DFAState nextState;
// 遍历 DFAState 中的每个 NFA 状态
for (const string& nfaState_name : dfaState.nfaStates) {
// 在这里遍历所有 NFA 状态的边
for (int i = 0; i < nfa.edgeCount; i++) {
edge currentEdge = nfa.edgeSet[i];
// 如果边的起始状态是当前状态,且边的转换符号等于输入符号,将目标状态加入 nextState
if (currentEdge.startName.nodeName == nfaState_name && currentEdge.tranSymbol == transitionSymbol&¤tEdge.tranSymbol!='#') {
nextState.nfaStates.insert(currentEdge.endName.nodeName);
}
}
}
// 为 nextState 分配一个唯一的名称
for (const string& nfaState_name : nextState.nfaStates) {
nextState.stateName += nfaState_name;
}
return nextState;
}
// 检查 DFA 状态是否在状态集合中,即dfaStates里有没有找到targetState
bool isDFAStateInVector(const vector<DFAState>& dfaStates, const DFAState& targetState) {
for (const DFAState& state : dfaStates) {
if (state.stateName == targetState.stateName) {
return true; // 找到匹配的状态
}
}
return false; // 没有找到匹配的状态
}
//检查转换边是否在边集合中,比如a->b是否已经在集合中
bool isTransitionInVector(DFAState dfaState, DFAState dfaNextState, char symbol,vector<DFATransition> dfaTransitions)
{
for (const DFATransition& transition : dfaTransitions) {
if (transition.fromState.stateName == dfaState.stateName && dfaNextState.stateName == dfaNextState.stateName&&symbol==transition.transitionSymbol) {
return true; //找到匹配的状态
}
}
return false;
}
void buildDFAFromNFA(const elem& NFA_Elem, vector<DFAState>& dfaStates, vector<DFATransition>& dfaTransitions) {
// 初始化 DFA 状态集合和转换关系
set<string> nfaInitialStateSet;
nfaInitialStateSet.insert(NFA_Elem.startName.nodeName);
DFAState dfaInitialState = eClosure(nfaInitialStateSet, NFA_Elem); // 计算 NFA 初始状态的 ε闭包
dfaStates.push_back(dfaInitialState);
// 开始构建 DFA
for (int i = 0; i < dfaStates.size(); i++) {//遍历当前已知的DFA状态集合dfaStates中的每一个状态
DFAState dfaState = dfaStates[i];
for (int j = 0; j < NFA_Elem.edgeCount; j++) {
char symbol = NFA_Elem.edgeSet[j].tranSymbol;
DFAState nextState = move(dfaState, symbol, NFA_Elem);
DFAState dfaNextState = eClosure(nextState.nfaStates, NFA_Elem);
if (!nextState.nfaStates.empty()) {
// 如果下一个状态不为空,且在 DFA 状态集合中还未添加,则加入 DFA 状态集合
if (!isDFAStateInVector(dfaStates, dfaNextState)) {
dfaStates.push_back(dfaNextState);
}
// 对于边也要去重,因为等于a的边可能会遍历到两次
// 如果当前边在 DFA 转换关系中还未添加,则加入 DFA 转换关系
if (!isTransitionInVector(dfaState, dfaNextState, symbol, dfaTransitions)) {
dfaTransitions.push_back({ dfaState, dfaNextState, symbol });
}
}
}
}
}
// 显示 DFA 状态和转移关系,包括起始和结束状态
void displayDFA(const vector<DFAState>& dfaStates, const vector<DFATransition>& dfaTransitions,string nfaEndName) {
cout << "DFA States:" << endl;
// 用于存储所有的转换符号,能够自动去重
set<char> transitionSymbols;
// 遍历 DFA 转换关系,将所有的转换符号加入 set 中
for (const DFATransition& transition : dfaTransitions) {
transitionSymbols.insert(transition.transitionSymbol);
}
// 输出所有的转换符号
cout << "Transition Symbols: ";
for (char symbol : transitionSymbols) {
cout << symbol << " ";
}
cout << endl;
for (const DFAState& state : dfaStates) {
cout << "State " << state.stateName << " (NFA States: ";
for (const string& nfaState_name : state.nfaStates) {
cout << nfaState_name << " ";
}
cout << ")";
if (state.stateName == dfaStates.front().stateName) {
cout << " (Initial State)";
}
if (state.stateName.find(nfaEndName) != std::string::npos) {
cout << " (Final State)";
}
cout << endl;
}
cout << "DFA Transitions:" << endl;
for (const DFATransition& transition : dfaTransitions) {
cout << "State " << transition.fromState.stateName << " --(" << transition.transitionSymbol << ")--> State " << transition.toState.stateName << endl;
}
}
//生成DFA的dot文件
void generateDotFile_DFA(vector<DFAState>& dfaStates, vector<DFATransition>& dfaTransitions, string nfaEndName) {
std::ofstream dotFile("dfa_graph.dot");
if (dotFile.is_open()) {
dotFile << "digraph DFA {\n";
dotFile << " rankdir=LR; // 横向布局\n\n";
dotFile << " node [shape = circle]; // 初始状态\n\n";
// 添加DFA状态
for (const auto& state : dfaStates) {
dotFile << " " << state.stateName;
dotFile << " [label=\"State " << state.stateName;
if (state.stateName == dfaStates.front().stateName){
dotFile << "\\n(startState)"; // 标记开始状态
if (state.stateName.find(nfaEndName) != std::string::npos) { // 如果状态包含NFA的结束状态
dotFile << "\\n(endState)\", shape = doublecircle";
}
dotFile << "];\n";
continue;
}else if (state.stateName.find(nfaEndName) != std::string::npos) { // 如果状态包含NFA的结束状态
dotFile << "\\n(endState)\", shape = doublecircle];\n";
// dotFile << "\", shape = doublecircle"; // 添加双圆圈形状属性
}else{
dotFile << "\"];\n";
}
}
dotFile << "\n";
// 添加DFA转移
for (const auto& transition : dfaTransitions) {
dotFile <<" " <<transition.fromState.stateName << " -> " << transition.toState.stateName << " [label=\"" << transition.transitionSymbol << "\"];\n";
}
dotFile << "}\n";
dotFile.close();
std::cout << "DFA DOT file generated successfully.\n";
}
else {
std::cerr << "Unable to open DOT file.\n";
}
}
/*下面是构造NFA的主要函数*/
//创建新节点
node new_node()
{
node newNode;
newNode.nodeName = nodeNum + 65;//将名字用大写字母表示
nodeNum++;
return newNode;
}
//打印NFA
void Display( elem Elem) {
cout << "NFA States:" << endl;
cout << "Start State: " << Elem.startName.nodeName << endl;
cout << "End State: " << Elem.endName.nodeName << endl;
cout << "NFA Transitions:" << endl;
for (int i = 0; i < Elem.edgeCount; i++) {
cout << "Edge " << i + 1 << ": ";
cout << Elem.edgeSet[i].startName.nodeName << " --(" << Elem.edgeSet[i].tranSymbol << ")--> ";
cout << Elem.edgeSet[i].endName.nodeName << endl;
}
cout << "End" << endl;
}
//生成NFAdot文件
void generateDotFile_NFA(const elem& nfa) {
std::ofstream dotFile("nfa_graph.dot");//创建dot文件
if (dotFile.is_open()) {
dotFile << "digraph NFA {\n";//开头声明,是一个有向图
dotFile << " rankdir=LR; // 横向布局\n\n";
dotFile << " node [shape = circle]; // 状态节点\n\n";//节点默认为圆形
dotFile << nfa.endName.nodeName << " [shape=doublecircle];\n";//结束状态节点为双圆圈形
// 添加 NFA 状态
dotFile << " " << nfa.startName.nodeName << " [label=\"Start State: " << nfa.startName.nodeName << "\"];\n";
dotFile << " " << nfa.endName.nodeName << " [label=\"End State: " << nfa.endName.nodeName << "\"];\n";
// 添加 NFA 转移
for (int i = 0; i < nfa.edgeCount; i++) {
const edge& currentEdge = nfa.edgeSet[i];
dotFile << " " << currentEdge.startName.nodeName << " -> " << currentEdge.endName.nodeName << " [label=\"" << currentEdge.tranSymbol << "\"];\n";//从起点到终点画一条有向边,并在边上标注转移符号
}
dotFile << "}\n";
dotFile.close();
std::cout << "NFA DOT file generated successfully.\n";
}
else {
std::cerr << "Unable to open NFA DOT file.\n";
}
}
int main() {
string Regular_Expression;
elem NFA_Elem;
cout << "请输入NFA的初始状态:";
cin >> NFA_Elem.startName.nodeName;
cout << "请输入NFA的终态:";
cin >> NFA_Elem.endName.nodeName;
cout << "请输入NFA的边数:" << endl;
cin>> NFA_Elem.edgeCount;
cout << "请输入NFA的转换方程(格式:起始状态,转换符号,目标状态):" << endl;
// cout << "输入完毕后,请输入#结束:" << endl;
for (int i = 0; i < NFA_Elem.edgeCount; ++i) {
cout << "Edge " << i + 1 << ": ";
cin >> NFA_Elem.edgeSet[i].startName.nodeName >> NFA_Elem.edgeSet[i].tranSymbol>> NFA_Elem.edgeSet[i].endName.nodeName ;
}
//显示
Display(NFA_Elem);
//生成NFAdot文件
generateDotFile_NFA(NFA_Elem);
// 初始化 DFA 状态集合和转换关系
vector<DFAState> dfaStates; //用于存储所有的DFA状态
vector<DFATransition> dfaTransitions; //用于存储DFA状态之间的转移
set<string> nfaInitialStateSet; //存储NFA的初始状态
buildDFAFromNFA(NFA_Elem, dfaStates, dfaTransitions);//从NFA构造DFA
// 显示 DFA
displayDFA(dfaStates, dfaTransitions,NFA_Elem.endName.nodeName);
//生成DFAdot文件
generateDotFile_DFA(dfaStates,dfaTransitions,NFA_Elem.endName.nodeName);
return 0;
}
代码实现效果如下:
生成的dot文件:
将dot转化为图片的命令:
生成的图片: