利用子集构造法实现NFA到DFA的转换
概述
NFA非有穷自动机,即当前状态识别某个转换条件后到达的后继状态不唯一,这种自动机不便机械实现,而DFA是确定有限状态的自动机,它的状态转换的条件是确定的,且状态数目往往少于NFA,所以DFA能够比较方便的机械实现且识别能力方面也和NFA相当。本次实验采用子集构造法来实现不带空弧的由NFA到DFA的转换。
子集构造法的算法如下:
设NFA为M=(K,Σ,f,S0,Z),则构造相应的DFA M′=(Q,Σ,f′,I0,F)
①取I0=S0;
②对于状态集Q中任一尚未标记的状态qi={Si1,Si2,…,Sim},Sik∈K,做:
(1) 标记qi;
(2) 对于每个a∈Σ,置
T=f({Si1,Si2,…,Sim},a)
qj=εCLOSURE(T)
(3) 若qj不在Q中,则将qj作为一个未加标记的状态添加到Q中,且把状态转移f′(qi,a)=qj添加到M′。
③重复进行步骤②,直到Q中不再含有未标记的状态为止。对于由此构造的Q,我们把那些至少含有一个Z中的元素的qi作为M′的终态。

对于如图所示的NFA其在文件中保存的信息如下

转成DFA之后的形式为

重命名为

程序整体思路
首先将文件中所给的NFA输入读入程序,在读入过程中将其以图的邻接表的形式保存,其中将状态转移条件记为该边的权值,每种状态记为图的结点,该状态识别状态转移条件(权值)之后到达的状态为该结点的邻接点。
对于上面的例子,将其读入程序中后该图在程序中的逻辑存储结构(图的邻接表)如图所示,其中邻接点中第一个数字表示权值,第二个数字表示所连的结点。

将图读入程序中后,再使用子集构造算法来完成由NFA到DFA的转化。
对于每种状态,其数据结构定义为
typedef struct state
{
set<int> Set;
char name;
}state;
其中set里存放该状态识别某个条件后所能到达的状态集合的下标,name里存该状态重命名后的名字。
这些状态保存在状态数组States[max]中,状态数组States[max]数据结构定义为
state States[max];
子集构造法的过程就是不断向状态数组States[ ]中,添加识别某个条件后,新的未出现的状态的过程。
程序中函数说明
void creatph(algraph &g,FILE *fpr):将文件内容读入程序,并将其转换为图的邻接表子函数。
int change(algraph g,char p):将图中结点转化为对应下标子函数。
state move(state s,int n,algraph g):求当前状态集合的转移集合,即求s状态识别字母n之后的状态集合。
int equalSet(state m,state n):比较两个状态的set集合内容是否相等,不相等返回0,相等返回1。
void inStates(state &s):判断当前状态是否在States数组中存在,若存在,进行改名;若不存在,改名后加入States数组。
void changeToD(algraph g,FILE *fpw):由NFA转到DFA的主控程序子函数。
程序输入如下图所示

程序输出如下图所示

代码清单
#include<stdio.h>
#include<malloc.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include<set> using namespace std; #define max 50//定义结点最大数量
typedef char vertype;//定义结点值域为字符类型
char buf[];//定义读文件内容时,程序缓冲数组
int num;//记录有穷字母表元素的个数
int length;//记录States数组的长度 typedef struct arcnode//图的边信息
{
int adjvex;
int weight;//边所对应的权值
struct arcnode *next;
}arcnode; typedef struct vnode//图的结点类型定义
{
vertype data;
arcnode *next;
}vnode,adjlist[max]; typedef struct//图的定义
{
adjlist a;
int vexnum,arcnum;
}algraph; typedef struct state//状态的定义
{
set<int> Set;
char name;
}state; state States[max]; int change(algraph g,char p)//将图中结点转化为对应下标
{
int i;
for(i=;i<g.vexnum;i++)
{
if(p==g.a[i].data)
return i;
}
return -;
} void creatph(algraph &g,FILE *fpr)
{
int line = ;
while(!feof(fpr))
{
fgets(buf,,fpr);
if(strlen(buf)>)//获取文件中图的结点个数
{
int i = ;
while(buf[i]==' ')
{
i++;
} g.a[line].data=buf[i];
g.a[line].next=NULL;
line++;
}
}
g.vexnum=line; rewind(fpr);//将文件指针返回到开头位置
line = ;
arcnode *s; while(!feof(fpr))//再次扫描文件将边的信息添上,构造图
{
int weight=;//边所对应的权值,每一行权值都从0开始
fgets(buf,,fpr);
if(strlen(buf)>)
{
for(int i=;i<strlen(buf)-;i++)
{
if(buf[i]=='{')
{
weight++;
if(num<weight)
num=weight; i++;
if(buf[i]=='N')
i=i+; while(buf[i]!='}')
{
if(buf[i]!=',')
{
//cout<<buf[i];////////////////////////////////
int x = change(g,buf[i]); s=(arcnode *)malloc(sizeof(arcnode));
s->adjvex=x;
s->weight=weight;
s->next=g.a[line].next;
g.a[line].next=s;
//cout<<line;////////////////////////////////
}
i++;
}
}
}
line++;
}
} } state move(state s,int n,algraph g)//求当前状态集合的转移集合,即求s状态识别字母n之后的状态集合
{
state temp;
arcnode *m;
set<int>::iterator itr;//迭代器
for(itr = s.Set.begin();itr!=s.Set.end();itr++)//遍历当前s状态中集合元素
{
int i = *itr;
m = g.a[i].next;
while(m)
{
if(m->weight==n)
{
temp.Set.insert(m->adjvex);//cout<<m->adjvex<<" ";
// temp.name=s.name+1;//cout<<temp.name<<endl;
}
m=m->next;
}
}
return temp;
} int equalSet(state m,state n)//比较两个状态的set集合内容是否相等
{
int flag = ;
if(m.Set.size()!=n.Set.size())
{
flag = ;
return flag;
} set<int>::iterator itrm;
set<int>::iterator itrn;
for(itrm = m.Set.begin(),itrn = n.Set.begin();itrm!=m.Set.end();itrm++,itrn++)
{
int m = *itrm;
int n = *itrn; if(m!=n)
{
flag = ;
break;
}
}
return flag;
} void inStates(state &s)//判断当前状态是否在States数组中存在,若存在,进行改名;若不存在,改名后加入States数组
{
int flag = ;
if(length==)
{
States[]=s;
States[].name='A';
length++;
}
else
{
for(int i=;i<length;i++)
{
//cout<<equalSet(States[i],s);
if(equalSet(States[i],s)==)//若存在,进行改名
{
s.name=States[i].name;
flag = ;
break;
}
} if(flag == )//若不存在,改名后加入States数组
{
s.name=States[length-].name+;
States[length]=s;
length++;
}
}
} void changeToD(algraph g,FILE *fpw)
{
state s,temp;
s.Set.insert();
s.name='A'; inStates(s); for(int i=;i<length;i++)
{
cout<<"{";
fprintf(fpw,"{"); set<int>::iterator itr;//迭代器
for(itr = States[i].Set.begin();itr!=States[i].Set.end();itr++)//遍历当前s状态中集合元素
{
int i = *itr;
cout<<g.a[i].data<<",";
fprintf(fpw,"%c,",g.a[i].data);
} cout<<"}";
fprintf(fpw,"}"); cout<<States[i].name;
fprintf(fpw,"%c",States[i].name); for(int j=;j<=num;j++)
{
temp = move(States[i],j,g);
inStates(temp);
//查看temp状态的set集合
/*
set<int>::iterator itr;//迭代器
for(itr = temp.Set.begin();itr!=temp.Set.end();itr++)//遍历当前s状态中集合元素
{
int i = *itr;
cout<<i<<" ";
}*/
cout<<temp.name;
fprintf(fpw,"%c",temp.name);
}
cout<<endl;
fprintf(fpw,"\n");
}
} int main()
{
algraph g; FILE *fpr = fopen("F:\\test.txt","r");
FILE *fpw = fopen("F:\\testOutput.txt","w"); /* FILE *fpr = fopen("test.txt","r");
FILE *fpw = fopen("output.txt","w");*/ creatph(g,fpr); //create测试
/*
for(int i=0;i<g.vexnum;i++)
{
cout<<g.a[i].data<<endl;////////////////// }
*/ changeToD(g,fpw);
//move测试
/*
state s;
s.Set.insert(0);
s.Set.insert(2);
s.Set.insert(3);
s.mark=1;
s.name='B'; move(s,2,g);
*/
return ;
}
利用子集构造法实现NFA到DFA的转换的更多相关文章
- 子集构造法实现NFA的确定化
功能: 采用子集构造算法实现NFA的确定化 输入:读取NFA的文件(文件名test.txt), 文件格式: 第一列表示状态名,第二列和第三列分别表示输入字符a和b到达的状态 输出:确定化后的DFA( ...
- NFA到DFA实例
下面图使用NFA表示的状态转换图, 使用子集构造法,有如下过程, ε-closure(0) = {0, 1, 2, 3, 4, 6, 7}初始值,令为AA = {0, 1, 2, 3, 4, 6, 7 ...
- NFA转DFA - json数字识别
json的主页上,提供了number类型的符号识别过程,如下: 图片引用:http://www.json.org/json-zh.html 实际上这张图片表示的是一个状态机,只是状态没有标出来.因为这 ...
- 计算理论:NFA转DFA的两种方法
本文将以两种方法实现NFA转DFA,并利用C语言实现. 方法二已利用HNU OJ系统验证,方法一迷之WA,但思路应该是对的,自试方案,测试均通过. (主要是思路,AC均浮云,大概又有什么奇怪的Case ...
- 【译】N 皇后问题 – 构造法原理与证明 时间复杂度O(1)
[原] E.J.Hoffman; J.C.Loessi; R.C.Moore The Johns Hopkins University Applied Physics Laboratory *[译]* ...
- 求子串-KPM模式匹配-NFA/DFA
求子串 数据结构中对串的5种最小操作子集:串赋值,串比较,求串长,串连接,求子串,其他操作均可在该子集上实现 数据结构中串的模式匹配 KPM模式匹配算法 基本的模式匹配算法 //求字串subStrin ...
- LeetCode42题,单调栈、构造法、two pointers,这道Hard题的解法这么多?
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第23篇文章. 今天来看一道很有意思的题,它的难度是Hard,并且有许多种解法. 首先我们来看题面,说是我们有若 ...
- nfa转dfa,正式完成
为了加速转换的处理,我压缩了符号表.具体算法参考任何一本与编译或者自动机相关的书籍. 这里的核心问题是处理传递性闭包,transitive closure,这个我目前采取的是最简单的warshall算 ...
- NFA和DFA区别
一个数据块的访问时间等于寻道时间.旋转延迟时间和数据传输时间三者之和: NFA和DFA区别: 一个状态如A,遇0可以转换到下一个状态B或C,因为选择多所以不确定,因此为不确定的有限自动机: 一个状态还 ...
随机推荐
- Dell M102ZD-128 —— 拿XP拯救你
查过新浪博客上的记录: http://blog.sina.com.cn/s/articlelist_1259160330_7_1.html 2011年6月买了这台 Dell Inspiron M102 ...
- JVM-Java程序性能监控-初级篇
前篇 - 小伙们都知道,java程序的性能监控主要是针对jvm中heap的监控~ 那么在做压力测试时如何对heap.线程等一系列的指标进行的监控的呢? 首先-你若不懂命令,那么就需要了解一套Java程 ...
- 开源中文分词工具探析(五):FNLP
FNLP是由Fudan NLP实验室的邱锡鹏老师开源的一套Java写就的中文NLP工具包,提供诸如分词.词性标注.文本分类.依存句法分析等功能. [开源中文分词工具探析]系列: 中文分词工具探析(一) ...
- jeesite学习(一) common部分(1)
我们按照先细节后整体的方式来进行学习,即先了解各个包中包含的内容,再从整体上看各个包之间的关系. 0 common中的包 先看jeesite的common组件,common中共包含14个包(如下图), ...
- HTML5学习笔记<五>: HTML表单和PHP环境搭建
HTML表单 1. 表单用于不同类型的用户输入 2. 常用的表单标签: 标签 说明 <form> 表单 <input> 输入域 <textarea> 文本域 < ...
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(二)Log4j讲解与整合
日常啰嗦 上一篇文章主要讲述了一下syso和Log间的一些区别与比较,重点是在项目的日志功能上,因此,承接前文<Spring+SpringMVC+MyBatis+easyUI整合优化篇(一)Sy ...
- 我所理解的javascript中函数的作用域和作用域链
本文为原创,转载请注明出处: cnzt 文章:cnzt-p 写在前面 一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看 ...
- Oracle的基本学习(二)—基本查询
一.基本查询语句 (1)查看当前用户 show user; (2)查看当前用户下的表 select * from tab; (3)查看员工表的结构 desc emp; (4)选择全部列 S ...
- JDBC基础学习(六)—数据库连接池
一.数据库连接池介绍 1.数据库连接池的缘由 对于一个简单的数据库应用,由于对于数据库的访问不是很频繁.这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什 ...
- WPF 杂谈——开篇简言。
这俩年多来笔者一直在从事关于WPF的开发.虽然不能说是专家级别的.但是对于WPF的应用还是有一定的了解.论他的灵活性决对不在WinForm之下.WPF的出现更是引发一段热议.他的何去何从更是让很多人感 ...