编译原理实验:NFA转化为DFA

简介: 编译原理实验:NFA转化为DFA

一:实验目的

将NFA转化为DFA

二:实验内容

编程序实现NFA转化为DFA。

三:实验过程

1.实验步骤

(1)源代码

#include <iostream>
#include <fstream>
#include <queue>
#include <cstring>
#include <map>

using namespace std;

int i = 0;

struct Node {
   
   
    //DFA节点
    int s;
    bool flag;
    //标记一个DFA节点集合是否包含NFA结束态,即表示DFA中是否是一个结束态
    Node(int ss, bool f) {
   
   
        s = ss;
        flag = f;
    }
};

struct Edge {
   
   
    //DFA边
    int from, to;
    char c;
    Edge(int x, int y, char z) {
   
   
        from = x;
        to = y;
        c = z;
    }
};

const int MAX = 101;
//字符数
int zf;
//字符集
char zfj[MAX];
//状态数,0开始
int zt;
//起始和结束态
int Begin, End;
//存边
char G[MAX][MAX]; 
//标记NFA状态是否被访问,求闭包用到
int vis[MAX];
//DFA节点集
vector<Node> V;
//DFA边集
vector<Edge> edge;
//求过的闭包保存以后用
int eps_clos[MAX];
queue<int> eq;

//求eps闭包
int E_closure(int x) {
   
   
    if (eps_clos[x] != -1) {
   
   
        return eps_clos[x];
    }
    queue<int> q;
    memset(vis, 0, sizeof(vis));
    int S = 0;
    S = S | (1 << x);
    q.push(x);
    while (!q.empty()) {
   
   
        //BFS求闭包
        int v = q.front();
        q.pop();
        for (int w = 0; w < zt; w++) {
   
   
            if (G[v][w] == '#'&&!vis[w]) {
   
   
                vis[w] = 1;
                S |= (1 << w);
                q.push(w);
            }
        }
    }
    eps_clos[x] = S;
    return S;
}

int set_edge(int s, char c) {
   
   
    //求一个状态集吃字符到达的状态集
    int i, j;
    int S = 0;
    for (i = 0; i < zt; i++) {
   
   
        if ((s >> i) & 1) {
   
   
            for (j = 0; j < zt; j++) {
   
   
                if (G[i][j] == c)
                    S |= E_closure(j);
            }
        }
    }
    return S;
}

bool check(int s) {
   
   
    //检查DFA节点集是否出现过
    for (int i = 0; i < V.size(); i++) {
   
   
        if (V[i].s == s) return true;
    }
    return false;
}

bool is_end(int s) {
   
   
    //状态集是否包含终结点
    return (s >> End) & 1;
}

void ZJGZ() {
   
   
    //子集构造算法
    int i;
    queue<int> work;
    work.push(E_closure(0));
    //加入DFA节点集
    V.push_back(Node(E_closure(0), is_end(E_closure(0))));
    while (!work.empty()) {
   
   
        int v = work.front();
        work.pop();
        for (i = 0; i < zf; i++) {
   
   
            //遍历字符集
            //生成NFA吃完该字符所能到达的所有状态
            int s = set_edge(v, zfj[i]);
            if (s != 0) {
   
   
                edge.push_back(Edge(v, s, zfj[i]));
                if (!check(s)) {
   
   
                    V.push_back(Node(s, is_end(s)));
                    work.push(s);
                }
            }
        }
    }
}

void out_put(int i, int s, bool f) {
   
   
    printf("DFA状态:q%d 包含的NFA中的状态为:", i);
    for (int j = 0; j < zt; j++)
        if ((s >> j) & 1) printf("s%d ", j);
    if (f) printf("包含结束态\n");
    else printf("不包含结束态\n");
}

int main()
{
   
   
    memset(eps_clos, -1, sizeof(eps_clos));
    ifstream in("nfa.txt");
    ofstream out("dfa.txt");
    in >> zf;
    for (i = 0; i < zf; i++) {
   
   
        in >> zfj[i];
    }
    in >> zt;
    in >> Begin >> End;
    //NFA边数
    int n;
    in >> n;
    int x, y;
    char c;
    for (i = 0; i < n; i++) {
   
   
        in >> x >> c >> y;
        G[x][y] = c;
    }
    in.close();
    ZJGZ();

    out << zf << endl;
    for (i = 0; i < zf; i++) {
   
   
        out << zfj[i] << ' ';
    }
    out << endl;
    //DFA状态集映射到从0开始的状态标号
    map<int, int> mp;
    out << V.size() << endl;
    for (i = 0; i < V.size(); i++) {
   
   
        out << i << ' ' << V[i].flag << endl;
        mp[V[i].s] = i;
    }
    out << edge.size() << endl;
    for (i = 0; i < V.size(); i++)
        out_put(i, V[i].s, V[i].flag);
    for (i = 0; i < edge.size(); i++) {
   
   
        out << mp[edge[i].from] << ' ' << mp[edge[i].to] << ' ' << edge[i].c << endl;
        printf("状态q%d -> 状态q%d,吃入字符%c\n", mp[edge[i].from], mp[edge[i].to], edge[i].c);
    }
    out.close();
}

2.实验结果记录

(1)输入文本

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

(2)输出文本

3
a b c 
4
0 0
1 1
2 1
3 1
7
0 1 a
1 2 b
1 3 c
2 2 b
2 3 c
3 2 b
3 3 c

(3)运行结果

image.png

相关文章
|
自然语言处理 算法 编译器
编译原理复习一:正则表达式-NFA NFA-DFA DFA最小化(附题目与答案 超详细)
编译原理复习一:正则表达式-NFA NFA-DFA DFA最小化(附题目与答案 超详细)
1531 0
|
自然语言处理 编译器
编译原理复习五:属性文法与三地址码的生成(附题目与答案 超详细)
编译原理复习五:属性文法与三地址码的生成(附题目与答案 超详细)
1487 0
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习】层次聚类AGNES、二分K-Means算法的讲解及实战演示(图文解释 附源码)
【Python机器学习】层次聚类AGNES、二分K-Means算法的讲解及实战演示(图文解释 附源码)
816 0
|
11月前
|
机器学习/深度学习 人工智能 数据可视化
基于YOLOv8的100种中药分类识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
本项目基于YOLOv8实现100种中药材分类识别,配备完整数据集、训练代码与PyQt5图形界面,支持图片、视频及摄像头检测,提供开箱即用的中药智能识别系统。
基于YOLOv8的100种中药分类识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
|
Python
Python 中__new__方法详解及使用
__new__ 是 Python 中用于创建类实例的静态方法,在实例化对象时优先于 __init__ 执行。它定义在基础类 object 中,需传递 cls 参数(表示当前类)。__new__ 可决定是否使用 __init__ 方法或返回其他对象作为实例。特性包括:1) 在实例化前调用;2) 始终为静态方法。示例中展示了其用法及 Python2 和 Python3 的差异,强调了参数处理的不同。
548 10
|
数据采集 Java BI
笛卡尔积计算在关系数据库中的高效应用
笛卡尔积计算在关系数据库中的高效应用
|
机器学习/深度学习 编解码 监控
《深度解析转置卷积:原理与多元应用场景》
转置卷积(反卷积)是深度学习中用于上采样的重要操作,通过在输入间插入零填充以放大特征图。它广泛应用于图像生成、语义分割、超分辨率重建和CNN可视化等领域,能够学习更优的上采样方式。尽管计算成本较高且可能引入伪像,但其在多个任务中发挥着关键作用,并随着技术发展不断优化。
584 5
|
存储 编译器 C语言
C语言:数组名作为类型、作为地址、对数组名取地址的区别
在C语言中,数组名可以作为类型、地址和取地址使用。数组名本身代表数组的首地址,作为地址时可以直接使用;作为类型时,用于声明指针或函数参数;取地址时,使用取地址符 (&),得到的是整个数组的地址,类型为指向该类型的指针。
1442 4
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简
2718 1
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简