NFA确定化(C++实现)

NFA确定化

一、确定化算法——子集法

子集法伪代码

void deterDFA(T){  
		给T加标记,说明T要作为出发状态去查找输入符号的CLOSURE
		对于状态集合T,在输入符号为x下,跳转到的状态集合U 
		for(对于任意一个输入符号a){
				U = closure_T(move(T,a));
				if(U不在Dstate状态集合中){
					if(U包含NFA中的接受状态){
						  将U设置为接受状态 
				    }
				    将U加入DFA的状态集合,DFA状态数目加1
				}
				对当前状态T和输入符号a构造状态转换到达状态U
		}
}

二、函数说明

1. void BuildGraph(string filename);

通过读入txt文件filename构建NFA的状态转换图;
读入格式详见“Graph – 说明.txt”。
其中,状态转换图中的边存储在Edge[i]中(type(Edge[i]) = pair<int, char>),i表示边的起点,pair中的int表示边的终点,pair中的char表示转换字符。

2. void add(int a, int b, char signal);

a, b, signal分别表示边的起点、终点、转换字符。

3. int findState(set a);

在总状态集合中查找是否存在状态集合a,如果存在则返回1,否则返回-1,即需要将该状态集合加入到总状态集合中。

4. set Graph::getClosure(set cur, char signal)

以cur为当前状态集合,寻找转换字符为signal的Closure。

5. set Graph::getClosure(set cur)

以cur为当前状态集合,寻找其ε-Closure。

6. set Graph::getClosure(int cur)

以cur为当前状态点,寻找其ε-Closure。

三、实现代码

1.Graph.h

#ifndef GRAPH_H
#define GRAPH_H
#include<cstring>
#include<iostream>
#include<fstream> 
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int N = 100;

class Graph
{
	public:
		//集合序号 
		char index;
		//状态数量 
		int StateNum;
		//初始点数量、终止点数量 
		int StartNum, StopNum;
		//转换函数数量,字符集大小 
		int TransNum, LetterSize;
		//终止状态集合,初始状态集合 
		int StopState[N], StartState[N];
		//字符集合 
		char LetterSet[N];
		//状态集合 
		set< pair<char, set<int> > > stateSet;
		//状态队列 
		queue< set<int> > stateQueue;
		//当前状态集合 
		set<int> currentState;
		//转换集合 
		vector<pair<int, char> > Edge[N];
		Graph();
		//建图 
		void BuildGraph(string filename);
		//添加转换条件 
		void add(int a, int b, char signal);
		//NFA确定化 
		void deterDFA(int start);
		//状态查找函数 
		int findState(set<int>);
		//重载求闭包函数 
		set<int> getClosure(int cur);
		set<int> getClosure(set<int> cur);
		set<int> getClosure(set<int> cur, char signal);
		//展示结果 
		void showDFA();
	protected:
};

#endif

2.Graph.cpp

#include"Graph.h"

using namespace std;

Graph::Graph()
{
	//从A开始编状态集合名称 
	index = 'A';
}

void Graph::BuildGraph(string filename)
{
	ifstream in(filename);
	
	//读入状态数量 
	in>>StateNum;
	cout<<"StateNum:"<<StateNum<<endl;
	
	//读入终止状态 
	in>>StopNum;
	for(int i=0; i<StopNum; i++)
	{
		in>>StopState[i];
	}
	cout<<"StopNum:"<<StopNum<<endl;
	cout<<"StopState:";
	for(int i=0; i<StopNum; i++)
	{
		cout<<StopState[i]<<' ';
	}
	cout<<endl;
	
	//读入字符集合 
	in>>LetterSize;
	for(int i=0; i<LetterSize; i++)
	{
		in>>LetterSet[i];
	}
	cout<<"LetterSize:"<<LetterSize<<endl;
	cout<<"LetterSet:";
	for(int i=0; i<LetterSize; i++)
	{
		cout<<LetterSet[i]<<' ';
	}
	cout<<endl;
	
	//读入转换函数 
	in>>TransNum;
	for(int i=0; i<TransNum; i++)
	{
		int a, b;
		char w;
		in>>a>>w>>b;
		add(a, b, w);
	}
	cout<<"TransNum:"<<TransNum<<endl;
	cout<<"Trans:"<<endl;
	for(int i=0; i<StateNum; i++)
	{
		if(Edge[i].size()==0)	continue;
		for(auto k:Edge[i])
		{
			cout<<i<<' '<<k.second<<' '<<k.first<<endl;
		}
	}
}

//a代表起点,b代表终点,signal代表对应字符 
void Graph::add(int a, int b, char signal)
{
	Edge[a].push_back({b, signal});
}

//查找状态集中是否有当前状态 
int Graph::findState(set<int> cur) 
{
	for(auto k:stateSet)
	{
		if(k.second == cur)
			return 1;
	}
	return -1;
}


//求状态集合为cur,字符为signal的Closure 
set<int> Graph::getClosure(set<int> cur, char signal)
{
	set<int> newset;
	for(set<int>::iterator it = cur.begin(); it != cur.end(); it++)
	{
		for(auto k:Edge[*it])
		{
			//cout<<k.first<<' '<<k.second<<endl;
			if(k.second == signal)
				{
					newset.insert(k.first);
					//cout<<k.first<<endl;
				}
		}
	}
	return newset;
}

//求状态集合为cur的ε-Closure ('#'表示ε弧) 
set<int> Graph::getClosure(set<int> cur)
{
	set<int> newset = cur;
	queue<int> q;
	for(set<int>::iterator it = cur.begin(); it != cur.end(); it++)
		q.push(*it);
	while(q.size())
	{
		int t = q.front();
		q.pop();
		set<int> newele = getClosure(t);
		for(set<int>::iterator it = newele.begin(); it != newele.end(); it++)
		{
			q.push(*it);
			newset.insert(*it);
		}
	}
	return newset;
}

//求状态只有cur的ε-Closure 
set<int> Graph::getClosure(int cur)
{
	set<int> newset;
	for(auto k:Edge[cur])
	{
		if(k.second == '#')
			newset.insert(k.first);
	}
	return newset;
}

//NFA确定化 
void Graph::deterDFA(int start)
{
	//将初始状态加到当前状态集合 
	currentState.insert(start);
	//求ε-Closure得到I 
	currentState = getClosure(currentState);
	//将I加到状态集合和队列 
	stateSet.insert({index, currentState});
	stateQueue.push(currentState);
	cout<<"----------------------------------"<<endl;
	cout<<" I		Ia		Ib"<<endl;
	cout<<"----------------------------------"<<endl;
	//当状态集合队列不为空 
	while(stateQueue.size())
	{
		//取队头状态集合并弹出,依次求其I,Ia和Ib 
		auto temp = stateQueue.front();
		for(auto k:stateSet)
		{
			if(k.second == temp)
				cout<<" "<<k.first;
		}
		stateQueue.pop();
		//求Ia, Ib ... 
		for(int j=0; j<LetterSize; j++)
		{
			currentState = temp;
			//先求对应字符的Closure 
			currentState = getClosure(temp, LetterSet[j]);
			//再求该Closure的ε-Closure 
			currentState = getClosure(currentState);
			if(currentState.size() > 0)
			{
				if(findState(currentState)==-1)
				{
					//若求得的状态集合没有出现在总的状态集合和队列中,则加入 
					stateSet.insert({++index, currentState});
					stateQueue.push(currentState);
				}
				for(auto k:stateSet)
				{
					//取出该状态集合对应的字母名称 
					if(k.second == currentState)
						cout<<"\t\t"<<k.first;
				}
			}	
		}
		cout<<endl;
	}
	cout<<"----------------------------------"<<endl;
}

void Graph::showDFA()
{
	for(auto k:stateSet)
	{
		char id = k.first;
		auto state = k.second;
		cout<<id<<' ';
		
		for(set<int>::iterator it = state.begin(); it != state.end(); it++)
			cout<<*it<<' ';
		cout<<endl;
	}
}

3.main.cpp

#include <iostream>
#include"Graph.h"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
Graph G;
int main(int argc, char** argv) 
{
	//以文件形式读入 
	G.BuildGraph("Graph.txt");
	G.deterDFA(0);
	G.showDFA();
	return 0;
}

4.Graph.txt

11
1
10
2
a b
13
0 # 1
0 # 7
1 # 2
1 # 4
2 a 3
3 # 6
4 b 5
5 # 6
6 # 1
6 # 7
7 a 8
8 b 9
9 b 10

5.Graph - 说明.txt

//读入图状态个数
11

#读入图中终止状态个数和终止状态
1
10

#读入图中字符集大小和字符
2
a b

#读入转换条件个数和转换条件

13
0 # 1
0 # 7
1 # 2
1 # 4
2 a 3
3 # 6
4 b 5
5 # 6
6 # 1
6 # 7
7 a 8
8 b 9
9 b 10

#图构建成功

四、结果展示

NFA确定化结果
第一部分表示状态转换图终的边的信息,格式为(起点,转换符号,终点)。
第二部分表示确定化后的DFA M’。
第三部分表示每个字母代表的具体状态集合。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值