实验内容

  将非确定性有限状态自动机通过子集法构造确定性有限状态自动机。

实验步骤

  1,读入NFA状态。注意最后需要设置终止状态。

  2,初始态取空,构造DFA的l0状态,将l0加入未标记状态队列que

  3,当que不为空,取出一个状态依次做转移和取空操作,并构造出当前转移状态tmp。

  4,如tmp是一个新状态,加入到队列中。

  5,将构造出的DFA用作模式识别。

具体实现

  1,文件读入NFA状态转换图,采用vector存储。

  2,判断状态tmp是否是一个新的状态使用自定义hash方法。

  3,取空操作由于可以转移多步空字符,采用BFS实现。

  4,源代码编译环境MinGW GCC 8.2.0,c++11,低于c++11的版本不兼容。

  

#include <bits/stdc++.h>
using namespace std;
using P = pair<int, char>;
using ll = long long;
const int maxn = 1e3 + ;
const int prime = ;
const ll mod = 1e9 + ;
int getHash(const set<int> &s)
{
ll res = ;
for (auto x : s)
res = res * prime + x;
return res % mod;
}
struct FA
{
int debug = ;
char ep = '*';
set<char> chs;
int cnt = ; //最大状态数
vector<P> move[maxn];
set<int> end_state;
void setDebug(int de)
{
debug = de;
}
void addState(int s, int t, char ch)
{
move[s].emplace_back(t, ch);
if (ch != ep)
chs.emplace(ch);
cnt = max(cnt, max(s, t));
}
void addEndState(int s)
{
end_state.emplace(s);
}
void init(string file)
{
ifstream in(file);
int m;
in >> m; //边数
for (int i = ; i < m; i++)
{
int s, t;
char ch;
in >> s >> t >> ch;
addState(s, t, ch);
}
in >> m; //终止状态数目
for (int i = ; i < m; i++)
{
int st;
in >> st;
end_state.emplace(st);
}
if (debug)
cout << "done.\n";
}
set<int> bfs(set<int> s, char ch)
{
set<int> res;
res.clear();
queue<int> q;
while (!q.empty())
q.pop();
for (auto it : s)
q.emplace(it);
while (!q.empty())
{
int now = q.front();
q.pop();
if (res.count(now))
continue;
res.emplace(now);
int sz = move[now].size();
for (int i = ; i < sz; i++)
{
P tmp = move[now][i];
if (tmp.second == ch && !res.count(tmp.first))
q.emplace(tmp.first);
}
}
return res;
}
FA getDFA()
{
FA res;
set<int> st;
map<int, set<int>> mp;
unordered_map<int, int> mp2;
mp2.clear();
mp.clear();
st.clear();
st.emplace();
set<int> cur = bfs(st, ep); //初态计算,同时之后的st也代表了计算出来的状态
mp[] = cur; //初态hash值为0不用计算
queue<int> q;
st.clear();
q.emplace();
mp2[] = ;
int num = ; //状态数目
while (!q.empty())
{
int cur = q.front();
q.pop();
if (st.count(cur))
continue;
st.emplace(cur);
set<int> now = mp[mp2[cur]];
for (auto ch : chs)
{
set<int> to;
to.clear();
for (auto it : now) //转移
{
int sz = move[it].size();
for (int j = ; j < sz; j++)
{
P tmp = move[it][j];
if (tmp.second == ch)
to.emplace(tmp.first);
}
}
to = bfs(to, ep); //取空
int ha = getHash(to);
if (!st.count(ha))
{
q.emplace(ha);
mp2[ha] = num;
mp[num++] = to;
}
if (debug)
{
cout << mp2[cur] << "->" << mp2[ha] << " " << ch << "\n";
for (auto x : mp[mp2[cur]])
cout << x << " ";
cout << "\n";
for (auto x : mp[mp2[ha]])
cout << x << " ";
cout << "\n";
}
res.addState(mp2[cur], mp2[ha], ch);
}
}
for (int x = ; x < num; x++)
{
set<int> tmp = mp[x];
int f = ;
for (auto y : end_state)
if (tmp.count(y))
{
f = ;
break;
}
if (f)
res.addEndState(x);
}
return res;
}
int isok(string to)
{
int len = to.size();
int st = ;
for (int i = ; i < len; i++)
{
char ch = to[i];
int sz = move[st].size();
int f = ;
for (int j = ; j < sz && !f; j++)
{
P tmp = move[st][j];
if (tmp.second == ch)
{
f = ;
st = tmp.first;
}
}
if (!f)
break;
}
return end_state.count(st);
}
void diplayEnd()
{
for (auto x : end_state)
cout << x << " ";
cout << "\n";
}
} NFA, DFA;
int main()
{
NFA.init("prj2_5.txt");
DFA = NFA.getDFA();
cout << "Please enter matching sequence:\n";
string to; while (cin >> to && to != "#")
{
cout << (DFA.isok(to) ? "OK" : "NO") << "\n";
}
return ;
}

编译原理实验 NFA子集法构造DFA,DFA的识别 c++11实现的更多相关文章

  1. 《编译原理》LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析

    <编译原理>LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析 笔记 直接做题是有一些特定步骤,有技巧.但也必须先了解一些基本概念,本篇会通过例题形式解释概念,会容易理解和记忆,以 ...

  2. 编译原理实验之SLR1文法分析

    ---内容开始--- 这是一份编译原理实验报告,分析表是手动造的,可以作为借鉴. 基于  SLR(1) 分析法的语法制导翻译及中间代码生成程序设计原理与实现1 .理论传授语法制导的基本概念,目标代码结 ...

  3. [编译原理代码][NFA转DFA并最小化DFA并使用DFA进行词法分析]

    #include <iostream> #include <vector> #include <cstring> #include "stack" ...

  4. 编译原理-递归下降分析法 c程序部分的分析

    实验三 语法分析程序实验 专业 商软2班   姓名 黄仲浩  学号 201506110166 一. 实验目的      编制一个部分文法分析程序. 二. 实验内容和要求 输入:源程序字符串 输出:正确 ...

  5. 编译原理-确定有穷自动机(deterministic finite automata ,DFA)

    是一个五元组 M=(S,∑,f,S0,F) 其中 S:有穷状态集 ∑:输入字母表(有穷) f:状态转换函数.f(S,a)=S' 是单值部分映射,每个状态面临一个输入符号时,转入的后继状态是确定的. S ...

  6. 编译原理--05 用C++手撕PL/0

    前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...

  7. 编译原理-NFA构造DFA

    本题摘自北邮的编译原理与技术. 首先,根据此图构造状态转换表 表中第一列第一行表示从第一个符号B通过任意个空转换能到达的节点,Ia表示由此行的状态数组({B,5,1}可以看作0状态)经过一个a可以到达 ...

  8. 《编译原理》构造与正规式 (0|1)*01 等价的 DFA - 例题解析

    <编译原理>构造与正规式 (0|1)*01 等价的 DFA - 例题解析 解题步骤: NFA 状态转换图 子集法 DFA 的状态转换矩阵 DFA 的状态转图 解: 已给正规式:(0|1)* ...

  9. 编译原理之非确定的自动机NFA确定化为DFA

    1.设有 NFA M=( {0,1,2,3}, {a,b},f,0,{3} ),其中 f(0,a)={0,1}  f(0,b)={0}  f(1,b)={2}  f(2,b)={3} 画出状态转换矩阵 ...

随机推荐

  1. AVR单片机教程——EasyElectronics Library v1.1手册

    索引: bit.h delay.h pin.h wave.h pwm.h led.h rgbw.h button.h switch.h 主要更新: 用枚举类型替换了大部分宏定义: 添加了wave.h. ...

  2. win10 cnpm安装完之后一直说不是内部命令的原因

    找到cnpm的默认安装路径 一般默认的是 D:\Program Files\nodejs\node_modules 然后添加环境变量中 win10是在系统环境变量中切记不是在用户变量中.保存之后,重新 ...

  3. Win10下80端口被System占用导致Apache无法启动

    Windows10下80端口被PID为4的System占用导致Apache无法启动的分析与解决方案 方法/步骤     最近更新了Windows10,总体上来说效果还是蛮不错的,然而今天在开启Apac ...

  4. vertical-align之见

    ertical-align   英文翻译为垂直对齐 ,常用来应用于table 表格中文字的垂直居中:脱离表格后不常用: 有朋友问起:故总结记之: 开局一张图,下来全靠编 这是一个简单的四线表格,小学时 ...

  5. CSS定位与布局

    我们在编写网页代码时,首先应该做的就是设计好页面的布局形式,然后再往里面填充内容.网页布局的好与坏,直接决定了网页最终的展示效果.PC端常见的网页布局形式有两列布局.三列布局等.在CSS中,我们通常使 ...

  6. Flume 学习笔记之 Flume NG概述及单节点安装

    Flume NG概述: Flume NG是一个分布式,高可用,可靠的系统,它能将不同的海量数据收集,移动并存储到一个数据存储系统中.轻量,配置简单,适用于各种日志收集,并支持 Failover和负载均 ...

  7. MySql 8.0.12安装、配置

    1. 参考:① 菜鸟教程下载安装MySQl ② 8.0.12安装方法 以下是我遇到的问题: 2.执行 mysqd --initialize --console 后,这个时候运行突然报"无法启 ...

  8. spring-data-redis-cache 使用及源码走读

    预期读者 准备使用 spring 的 data-redis-cache 的同学 了解 @CacheConfig,@Cacheable,@CachePut,@CacheEvict,@Caching 的使 ...

  9. selenium + python + firefox 测试环境的搭建与配置

    对于做UI自动化,如果是纯编写一段自动化测试程序,那么后续的维护成本会较高.这种情况下,借助 selenium 这款自动化系测试工具,辅助于自己编写部分脚本,将是个不错的选择.selenium 本身支 ...

  10. Redis之数据类型及命令

    Redis(REmote DIctionary Server) 是一个遵守BSD协议.支持网络.可基于内存亦可持久化的日志型key-value存储系统. KEY 常用指令: 指令 注释 备注 exit ...