前文回顾

【编译原理】正则表达式转NFA

算法

来自龙书第二版

C++实现

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAX_TRANS 100
using namespace std;vector<char>characters;//输入字符集
int DFA_state_number=0;//DFA中状态数量
vector<vector<int>>transition(MAX_TRANS);//记录终态的名称变化(一对多)
int final_count=0;//终态数量
int trans_count=0;//transition大小//得到的状态集合
struct States
{vector<int>jset;
};//DFA状态转换关系
struct relation
{States* pre;char jchar;States* next;
};
//得到s闭包
void Eclosure(bigCell NFA,States *s)
{for(int i=0;i<s->jset.size();i++){for(int j=0;j<NFA.count;j++){if(NFA.edges[j].source.id==s->jset[i] && NFA.edges[j].symbol=='?'){s->jset.push_back(NFA.edges[j].target.id);}}}
}
//能够从状态集s出发通过字符tc转换到达的NFA状态集合,结果放在t中
void move(char tc,bigCell NFA,States* s,States* t)
{for(int i=0;i<s->jset.size();i++){for(int j=0;j<NFA.count;j++){if(NFA.edges[j].source.id==s->jset[i] && NFA.edges[j].symbol==tc)t->jset.push_back(NFA.edges[j].target.id);}}
}
//添加状态子集
bool add(vector<States*>allSet,States *newS)
{bool b=true;for(int i=0;i<allSet.size();i++){if(allSet[i]->jset==newS->jset)b=false;}return b;
}
//去除重复的DFA转换关系
bool addRel(vector<relation*>relVec,States* preS,char c,States*nextS)
{bool b=true;for(int i=0;i<relVec.size();i++){if(relVec[i]->pre->jset==preS->jset && relVec[i]->next->jset==nextS->jset&& relVec[i]->jchar==c)b=false;}return b;
}//状态名称合并并重命名
void Rename(vector<States*>allSet,States* tS,int &newS)
{//从1开始命名for(int i=0;i<allSet.size();i++){if(tS->jset==allSet[i]->jset)newS=i+1;}
}//数组去重
void only(int *a,int n,int* b)
{memset(b,0,sizeof(int)*n);char first=a[0];for(int i=0;i<n;i++){b[a[i]-first]=a[i];}final_count=a[n-1]-first+1;
}//主要函数
int* NFA2DFA(bigCell NFA,vector<vector<int>>&dfaT)
{States *newS=new States();newS->jset.push_back(NFA.start.id);//初始状态Eclosure(NFA,newS);//得到初始状态的闭包Ivector<States*>allSet(1,newS);//DFA所有状态集合,初值为I的Eclosureint sizeOfStrVec=1;vector<States*>strVec(1,newS);//存储每次闭包操作多出的状态集合vector<relation*>relVec;//状态转换关系的集合//还有新增状态while(sizeOfStrVec){int oldAllSet=allSet.size();//原本所有状态数for(int j=0;j<sizeOfStrVec;j++){//cout<<j;//遍历所有输入字符for(int i=0;i<NFA.count;i++){States *dest=new States();//含有输入字符的边if(NFA.edges[i].symbol!='?'){move(NFA.edges[i].symbol,NFA,strVec[j],dest);//从strVec[j]出发通过symbol到达的所有状态存在dest中Eclosure(NFA,dest);//U=dest//U不在状态总集中if(add(allSet,dest)&&dest->jset.size()!=0){allSet.push_back(dest);}//将U加入DFA转换关系中if(dest->jset.size()!=0){relation* rDest=new relation();rDest->pre=strVec[j];rDest->jchar=NFA.edges[i].symbol;rDest->next=dest;//新的转换关系不与已有的重复,则加入relVecbool isIn=addRel(relVec,rDest->pre,rDest->jchar,rDest->next);if(isIn){relVec.push_back(rDest);}}}}}//将新增状态加入strVec中strVec.clear();int newAllSet=allSet.size();for(int i=oldAllSet;i<allSet.size();i++){States* dest=new States();dest=allSet[i];strVec.push_back(dest);}sizeOfStrVec=strVec.size();}/*加上以下代码可输出转换过程*/
//    cout<<"状态转换如下:"<<endl;
//    vector<relation*>::iterator it;
//    for(it=relVec.begin();it!=relVec.end();it++)
//    {//        输出转换前状态
//        for(int i=0;i<(*it)->pre->jset.size()-1;i++)
//        {//            cout<<(*it)->pre->jset[i]<<",";
//        }
//
//        输出输入字符
//        cout<<(*it)->pre->jset[(*it)->pre->jset.size()-1]<<"     "<<(*it)->jchar<<"     ";
//
//        输出转换后状态
//        for(int i=0;i<(*it)->next->jset.size()-1;i++)
//        {//            cout<<(*it)->next->jset[i]<<",";
//        }
//        cout<<(*it)->next->jset[(*it)->next->jset.size()-1]<<endl;
//    }
//    cout<<endl;
//
//    输出状态重命名前后名称
//    int newName[MAX];
//    memset(newName,0,sizeof(char)*MAX);
//    cout<<"状态重命名如下:"<<endl;
//    for(int i=0;i<allSet.size();i++)
//    {//        newName[i]=i+1;
//        cout<<newName[i]<<":";
//        for(int j=0;j<allSet[i]->jset.size()-1;j++)
//        {//            cout<<allSet[i]->jset[j]<<",";
//        }
//        cout<<allSet[i]->jset[allSet[i]->jset.size()-1]<<endl;
//    }DFA_state_number=allSet.size();vector<relation*>DFA;//创建重命名后的新边集合for(int i=0;i<relVec.size();i++){relation* newRel=new relation();//改名int newPre,newNext;Rename(allSet,relVec[i]->pre,newPre);Rename(allSet,relVec[i]->next,newNext);//创建新边States* tpre=new States();States* tnext=new States();newRel->pre=tpre;newRel->next=tnext;newRel->pre->jset.push_back(newPre);newRel->next->jset.push_back(newNext);newRel->jchar=relVec[i]->jchar;DFA.push_back(newRel);}vector<relation*>::iterator rit;for(rit=DFA.begin();rit!=DFA.end();rit++){dfaT[(*rit)->pre->jset[0]][(*rit)->jchar]=(*rit)->next->jset[0];characters.push_back((*rit)->jchar);}//去除字符集重复元素sort(characters.begin(),characters.end());characters.erase(unique(characters.begin(), characters.end()), characters.end());//终态int l=allSet.size();int *accepted=new int[l];//memset(accepted,0,sizeof(int)*l);for(int i=0;i<l;i++){for(int j=0;j<allSet[i]->jset.size();j++){//cout<<allSet[i]->jset[j]<<endl;for(int k=0;k<NFA.end.size();k++){if(allSet[i]->jset[j]==NFA.end[k].id){accepted[final_count++]=i+1;transition[i+1].push_back(NFA.end[k].id);//记录终态重命名前后trans_count=i+2;//cout<<i+1<<" "<<transition[i+1][1]<<endl;}}}}int *outs=new int[final_count];only(accepted,final_count,outs);delete []accepted;delete newS;return outs;
}
int showDFA(vector<vector<int>>dfaT,int *accepted)
{cout<<"DFA信息:"<<endl;for(int i=1;i<=DFA_state_number;i++){for(int j=0;j<characters.size();j++){char c=characters[j];cout<<i<<" "<<c<<" "<<dfaT[i][c]<<endl;}}cout<<"可接受状态为:"<<endl;for(int i=0;i<final_count;i++){cout<<accepted[i]<<" ";}cout<<endl<<endl;
}

测试结果

输出结果为:DFA每一条边的 起点 转换字符 终点


P.S:要源码的人太多了,贴下百度网盘的链接,有需要的自己去下载吧
链接:https://pan.baidu.com/s/1oQhPT26zVZFLCabot0tk_g
提取码:gtdv

其他相关博文

词法分析

【编译原理】正则表达式转NFA
【编译原理】最小化DFA

语法分析

【编译原理】LR(0)分析方法(c++实现)
【编译原理】SLR(1)分析方法(c++实现)
【编译原理】LL(1)分析方法 生成语法树(c++实现)

【编译原理】NFA转DFA(子集构造法)相关推荐

  1. 编译原理: Subset Construction 子集构造法(幂集构造)(NFA转DFA)

    编译原理: Subset Construction 子集构造法(幂集构造)(NFA转DFA) 文章目录 编译原理: Subset Construction 子集构造法(幂集构造)(NFA转DFA) 简 ...

  2. 【编译原理】:NFA转变为DFA的子集构造法

    整体的步骤是三步:  一,先把正规式转换为NFA(非确定有穷自动机),  二,在把NFA通过"子集构造法"转化为DFA,  三,在把DFA通过"分割法"进行最小 ...

  3. 【编译原理】 NFA转变为DFA的子集构造法

    整体的步骤是三步:  一,先把正规式转换为NFA(非确定有穷自动机),  二,在把NFA通过"子集构造法"转化为DFA,  三,在把DFA通过"分割法"进行最小 ...

  4. 利用子集构造法实现NFA到DFA的转换

    概述 NFA非有穷自动机,即当前状态识别某个转换条件后到达的后继状态不唯一,这种自动机不便机械实现,而DFA是确定有限状态的自动机,它的状态转换的条件是确定的,且状态数目往往少于NFA,所以DFA能够 ...

  5. NFA到DFA的子集构造法

    摘录博客:https://blog.csdn.net/qq_23100787/article/details/50402643 整体的步骤是三步:  一,先把正规式转换为NFA(非确定有穷自动机),  ...

  6. NFA转变为DFA的子集构造法

    整体的步骤是三步: 一,先把正规式转换为NFA(非确定有穷自动机), 二,在把NFA通过"子集构造法"转化为DFA, 三,在把DFA通过"分割法"进行最小化. ...

  7. 编译原理: 最小化 DFA(划分) 验证 DFA(Kleene 闭包)

    编译原理: 最小化 DFA(划分) & 验证 DFA(Kleene 闭包) 文章目录 编译原理: 最小化 DFA(划分) & 验证 DFA(Kleene 闭包) 简介 参考 正文 示例 ...

  8. 子集构造法和含有空串的子集构造法

    子集构造法 子集构造法很简单. 消除空转移子集构造法  Design 闭包是自己+接受空串能到达的状态. DFA的开始状态时NFA的闭包 3.识别的语言:(a+c+e)(a+c+e)b+(a+c+e) ...

  9. java编程实现算符优先分析法,编译原理实验三-算符优先分析法

    编译原理实验3-算符优先分析法 #include #include #include #include #define SIZE 128 char priority[6][6]; //算符优先关系表数 ...

最新文章

  1. MotionEvent的getX(),getY()与getRawX(),getRawY()区别
  2. Android Camera设置setPreviewCallback实现onPreviewFrame接口实时截取每一帧视频流数据
  3. 您的连接不是私密连接
  4. Ascamp;Chr Converter v1.0.vbs
  5. java单线程上锁_关于Java多线程编程锁优化的深入学习
  6. 注意力是非常宝贵的资源
  7. 下载和安装CUDA和Cudnn(图文详解)
  8. BZOJ-1069 [SCOI2007]最大土地面积
  9. 海康威视Android SDK,并非萤石Android SDK
  10. 哈希库--uthash的详细讲解(附uthash相关头文件下载)
  11. 【C++】《C++ Primer Plus》--复习题、编程练习题答案
  12. 本地缓存下载文件,download的二次封装
  13. 实验三 循环程序设计
  14. 计算机上的mac是什么意思啊,Mac版是什么意思,Windows版是什么意思?
  15. 墙裂推荐,Python开发者不容错过的7个VS Code扩展
  16. Input框,禁止输入中文
  17. 平衡小车c语言程序,【全部开源】两轮平衡小车(原理图、PCB、程序源码、BOM等)...
  18. 利用机器学习进行放假预测
  19. html微信网页字体被放大问题
  20. 【转】关于SAP的用户出口 SAP的用户功能增强

热门文章

  1. 一个简单的OPPO商城页面
  2. 数据库原理第四章测验(标黑的为答案)
  3. 《玩转Deepin第一篇 · Deepin系统的介绍和安装》
  4. 比林志玲cute的katee
  5. 还要入驻美团酒店被抽成吗?微小程小程序给你自己的平台
  6. 洲际酒店集团与南方航空宣布会籍匹配计划
  7. length属性和length()方法
  8. python熊猫图案_Python-熊猫
  9. 万向和肖风的区块链版图
  10. windows2008 R2安装LoadRunner 11提示WindowsInstaller存储空间不足解决方法