实验内容

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

实验步骤

  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. vue平行组件传值

    平行组件传值 通过平行组件传值可以实现任何情境下的传值,包括(父传子,子传父) 代码示例 <!DOCTYPE html> <html lang="en"> ...

  2. Spring Boot 2.X(六):Spring Boot 集成Redis

    Redis 简介 什么是 Redis Redis 是目前使用的非常广泛的免费开源内存数据库,是一个高性能的 key-value 数据库. Redis 与其他 key-value 缓存(如 Memcac ...

  3. ssrf漏洞学习(PHP)

    自己最近原本是想深入的学习一下关于xss.csrf的东西的,可是感觉这些东西需要有很好的js的基础来进行学习..还有感觉自己感觉也差不多该要学习内网渗透了..正好ssrf在内网这一块也是比较有用的.于 ...

  4. 02-11 RANSAC算法线性回归(波斯顿房价预测)

    目录 RANSAC算法线性回归(波斯顿房价预测) 一.RANSAC算法流程 二.导入模块 三.获取数据 四.训练模型 五.可视化 更新.更全的<机器学习>的更新网站,更有python.go ...

  5. python编程基础之二十七

    列表生成式:[exp for iter_var in iterable] 同样也会有字典生成式,集合生成式,没有元组生成式,元组生成式的语法被占用了 字典生成式,集合生成式,就是外面那个括号换成{}  ...

  6. 深入理解C# 委托(delegate)-戈多编程

    今天来谈谈委托,深入理解委托,本文来自各大神经验总结. 1.委托是什么? 委托类型的声明与方法签名相似. 它有一个返回值和任意数目任意类型的参数,是一种可用于封装命名方法或匿名方法的引用类型. 委托类 ...

  7. ZGC gc策略及回收过程-源码分析

    源码文件:/src/hotspot/share/gc/z/zDirector.cpp 一.回收策略 main入口函数: void ZDirector::run_service() { // Main ...

  8. Redis 的底层数据结构(整数集合)

    当一个集合中只包含整数,并且元素的个数不是很多的话,redis 会用整数集合作为底层存储,它的一个优点就是可以节省很多内存,虽然字典结构的效率很高,但是它的实现结构相对复杂并且会分配较多的内存空间. ...

  9. 代码审计-YXcms1.4.7

    题外: 今天是上班第一天,全都在做准备工作,明天开始正式实战做事. 看着周围稍年长的同事和老大做事,自己的感觉就是自己还是差的很多很多,自己只能算个废物. 学无止境,我这样的垃圾废物就该多练,保持战斗 ...

  10. 2019关于phpstudy软件后门简单分析

    2019.9.20得知非官网的一些下载站中的phpstudy版本存在后门文件   说是官网下的就没有后门 20号出现的新闻 今天phpstudy官网21号又更新一波 不太好说这是什么操作哦 此地无银三 ...