燕山大学编译课设-NFA转DFA以及最小化DFA

网上实在找不到相关的能直接使用的代码,所以就放上供大家参考。代码有点长,不过加了注释,而且学分也不高,我就不做目录了。另外在DFA最小化时没完成识别不可到达和不可终止的状态,如果时间充裕可以实现一下是一个加分项。

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set> 
#include <queue> 
#include <deque>
#include <map>
#include <unordered_map>
using namespace std;
const int N = 110;
typedef pair<int, int> PII;

void MyPrint(set<int> T);
void MyPrint();
int find(vector<set<int>> DFA, set<int> U);
bool Segment(pair<set<int>, int> se, int i);
int Serach(int S, string s);
int Serach(vector<pair<set<int>, int>> segment, int v);
int find(pair<set<int>, int> seg, string a);
int FindLoc(set<int> Q);
void MyPrint_Temp(vector<pair<set<int>, int>> segment);

struct Edge
{
    int v, next;
    string a;
}edge[N];
int head[N], idx;

vector<string> xiTa;//字母表
int k, st, ed;//状态个数和开始状态
vector<int> State;//状态节点
set<int> St, Ed;
set<int> eClosure[N];
int m;

void AddEdge(int u, string a, int v)
{
    edge[idx].v = v;
    edge[idx].a = a;
    edge[idx].next = head[u];
    head[u] = idx++;

}

void init()
{
    memset(head, -1, sizeof head);

    cout << "请输入状态个数 和 开始状态个数 以及 结束状态个数" << endl;
    cin >> k >> st >> ed;
    cout << "请输入状态的编号:" << endl;
    for (int i = 0; i < k; i++) { int s; cin >> s; State.push_back(s); }
    cout << "请输入开始状态" << endl;
    for (int i = 0; i < st; i++) { int s; cin >> s; St.insert(s); }
    cout << "请输入结束状态" << endl;
    for (int i = 0; i < ed; i++) { int s; cin >> s; Ed.insert(s); }

    cout << "请输入字母表个数(除 e 外)" << endl;
    cin >> m;

    cout << "请输入字母表字母" << endl;
    for (int i = 0; i < m; i++)
    {
        string a; cin >> a;
        xiTa.push_back(a);
    }
    cout << "请输入状态转换弧, 格式为(当前状态 输入符号 后继状态), 以 0 e 0 结束, 其中 e 表示空符号" << endl;
    int d, h; string a;
    while (cin >> d >> a >> h && !(d == 0 && a == "e" && h == 0))
    {
        AddEdge(d, a, h);
    }
}

void E_Closure()
{
    bool vis[N];
    cout << endl << "---------------------" << endl << "NFA状态的E_Closure如下:" << endl;
    for (auto i : State)
    {
        memset(vis, false, sizeof vis);
        queue<int> q;
        eClosure[i].insert(i);
        q.push(i);
        while (q.size())
        {
            int k = q.front();
            q.pop();
            // if (vis[k]) continue;
            // vis[k] = 1;
            for (int j = head[k]; j != -1; j = edge[j].next)
            {
                string a = edge[j].a; int v = edge[j].v;
                if (a == "e" && !vis[v])
                {
                    vis[v] = true;
                    eClosure[i].insert(v);
                    q.push(v);
                }
            }
        }
        cout << i << " 的E_Closure为: ";
        MyPrint(eClosure[i]); cout << endl;
    }
}

set<int> Move(set<int> T, string a)
{
    set<int> t;
    for (auto k : T)
    {
        for (int i = head[k]; i != -1; i = edge[i].next)
        {
            string w = edge[i].a; int v = edge[i].v;
            if (w == a) t.insert(v);
        }
    }
    return t;
}

set<int> E_Closure(set<int> T)
{
    set<int> t;
    for (auto k : T)
    {
        t.insert(eClosure[k].begin(), eClosure[k].end());
    }
    return t;
}


vector<set<int>> DFA_1;
deque<set<int>> qTemp;// 状态确定, 在MyPrint更方便
vector<pair<PII, string>> DFA_2;// DFA的边
void Solve()//子集法构造DFA
{
    
    DFA_1.push_back(E_Closure(St));//将K0的e-closure放入集合DFA

    int cnt = 0;
    while (cnt < DFA_1.size())
    {
        auto temp = DFA_1[cnt];
        qTemp.push_back(temp); // 便于以后输出矩阵
        for (auto a : xiTa)
        {
            set<int> U;
            U = Move(temp, a);
            U = E_Closure(U);
            qTemp.push_back(U); // 便于以后输出;
            
            if (find(DFA_1, U) == -1)
            {
                DFA_1.push_back(U);
            }
            int location = find(DFA_1, U);// 先放再找location否则可能为 -1;
            DFA_2.push_back({ { cnt, location }, a });
        }
        cnt++;
    }
}
int find(vector<set<int>> DFA, set<int> U)
{
    for (int i = 0; i < DFA.size(); i ++)
    {
        if (DFA[i] == U) return i;
    }
    return -1;
}


set<int> dfaEd;// 确定化后dfa的终止状态
void MyPrint(vector<set<int>> DFA)
{
    cout << endl << "DFA矩阵表示" << endl << "-----------------------------" << endl;

    for (auto a : xiTa) cout << "                          " << a;
    puts("");


    for (int i = 0; i < DFA.size(); i++)
    {
        cout << 'T' << i << ": ";
        MyPrint(DFA[i]);
        qTemp.pop_front();              // 队列里包括DFA
        for (auto a : xiTa)
        {
            cout << "           T" << FindLoc(qTemp.front()) << " ";
            
            MyPrint(qTemp.front());
            qTemp.pop_front();
        }
        cout << endl;

        for (auto j : Ed)// 判断DFA的终止状态
            if (DFA[i].end() != DFA[i].find(j)) { dfaEd.insert(i); break; }
    }


    cout << endl << "DFA的开始状态为: T0" << endl;
    cout << "DFA的终止状态为:";
    for (auto i : dfaEd)
    {
        cout << " T" << i << ',';
    }
    cout << '\b' << " " << endl;
}

int FindLoc(set<int> Q)//DFA确定化后的位置
{
    for (vector<set<int>>::iterator it = DFA_1.begin(); it != DFA_1.end(); it ++)
    {
        if (Q == *it) return it - DFA_1.begin();
    }
}


void MyPrint(set<int> T)
{
    cout << "{";
        for (set<int> :: iterator it = T.begin(); it != T.end(); it++)
            cout << *it << ",";
    cout << '\b' << "}";//<< endl;
}

void MyPrint()
{
    cout << endl << "NFA表示为:" << endl << "--------------------" << endl;
    for (auto a : xiTa) cout << "          " << a;
    cout << "          e(空字符)";
    puts("");

    for (auto s : State)
    {
        cout << s;
        for (auto a : xiTa)
        {
            cout << "          ";
            for (int i = head[s]; i != -1; i = edge[i].next)
            {
                int v = edge[i].v; string A = edge[i].a;
                if (A == a)
                    cout << " " << v;
            }
        }
        cout << "        ";
        for (int i = head[s]; i != -1; i = edge[i].next)
        {
            int v = edge[i].v; string A = edge[i].a;
            if (A == "e")
                cout << " " << v;
        }
        cout << endl;
    }

    cout << "NFA开始状态为:";
    for (auto s : St) cout << s << ',';
    cout << '\b' << " " << endl;

    cout << "结束状态为:";
    for (auto e : Ed) cout << e << ',';
    cout << '\b' << " " << endl;
}


vector<pair<set<int>, int>> segment; // 分割后的状态集合
void SolveMin()// 分割法
{
    set<int> dfaSt;// 非终态
    for (int i = 0; i < DFA_1.size(); i++)
    {
        if (dfaEd.end() == dfaEd.find(i))dfaSt.insert(i);
    }
    segment.push_back({ dfaSt, segment.size() });
    segment.push_back({ dfaEd, segment.size() });
    
    int cnt = 1;
    cout << endl << "分割法最小化过程" << endl << "---------------------" << endl;
    cout << "第" << cnt++ << "次  ";
    MyPrint_Temp(segment);
    for (int i = 0; i < segment.size();)
    {
        if (Segment(segment[i], i))
        {
            i = 0;
            cout << "第" << cnt++ << "次  ";
            MyPrint_Temp(segment);
        }
        else i++;
    }
}

void MyPrint_Temp(vector<pair<set<int>, int>> segment)
{
    for (auto K : segment)
    {
        cout << "{";
        for (auto U : K.first)
            cout << U << ',';
        cout << '\b' << "}      ";
    }
    cout << endl;
}

bool Segment(pair<set<int>, int> se, int i)//分割函数
{
    for (auto a : xiTa)
    {
        unordered_map<int, set<int>> temp;
        for (auto S : se.first)
        {
            int v = Serach(S,a);//状态的转移状态
            int V = Serach(segment, v);// 每个状态的转移状态所在的子集号
            temp[V].insert(S);
        }

        if (temp.size() > 1)// 只有分割了才放入
        {
            //删除原来的子集并且更新子集号
            segment.erase(segment.begin() + i);
            for (int i = 0; i < segment.size(); i ++)
                segment[i].second = i;

            // 将分割的子集加入
            for (auto it = temp.begin(); it != temp.end(); it++)
            {
                segment.push_back({ (*it).second , segment.size() });
            }
            return true;
        }
    }
    return false;
}
int Serach(int S, string s)// 每个状态的转移状态
{
    for (auto K : DFA_2)
    {
        int u = K.first.first; int v = K.first.second; string a = K.second;
        if (S == u && s == a) return v;
    }
    return -1;
}

int Serach(vector<pair<set<int>, int>> segment, int v)// 每个转移状态所在子集号
{
    for (auto K : segment)
    {
        if (K.first.find(v) != K.first.end()) return K.second;
    }
    return -1;//没有找到
}



set<int> dfaMEd;// 最小化后的结束状态
void Simplify(vector<pair<set<int>, int>> &segment)//合并状态
{
    for (auto &K : segment) // 把多余要合并的状态删了
        if (K.first.end() != K.first.find(0))
        {
            K.first.clear(); K.first.insert(0);
        }
        else
        {
            int t = *K.first.begin();//只留一个状态即可
            K.first.clear(); K.first.insert(t);
        }
}

void MyPrint(vector<pair<set<int>, int>> segment)
{
    cout << endl << "DFA最小化的矩阵表示" << endl << "-----------------------------" << endl;

    for (auto a : xiTa) cout << "          " << a;
    puts("");

    for (auto U : segment)
    {
        int i = *U.first.begin();
        cout << "T" << i;
        for (auto a : xiTa)
        {
            for (auto E : DFA_2)// 分割前的状态图
            {
                if (E.first.first == i && E.second == a)
                {
                    cout << "        T" << E.first.second;
                    break;
                }
            }
        }
        cout << endl;

        //结束状态
        if (dfaEd.end() != dfaEd.find(i)) dfaMEd.insert(i);
    }

    cout << endl << "DFA最小化的开始状态为:T0" << endl;
    cout << endl << "DFA最小化的终止状态为:";
    for (auto k : dfaMEd) cout << " T" << k << ',';
    cout << '\b' << " " << endl;
}


int main()
{
    // 确定化
    init();

    MyPrint(); // 打印NFA

    E_Closure(); // 求初始状态的E_Closure

    Solve();// 子集法求DFA

    MyPrint(DFA_1); // 矩阵打印DFA

    //最小化
    SolveMin(); //分割

    Simplify(segment); //状态合并

    MyPrint(segment);
    return 0;
}

下面是测试数据(注意每个提示输入别输入错了):

状态个数 11,开始状态 0, 终止状态 10
节点编号 0~10
0 e 7
0 e 1
1 e 2
1 e 4
2 a 3
3 e 6
4 b 5
5 e 6
6 e 7
6 e 1
7 a 8
8 b 9
9 b 10
0 e 0



状态个数 7,开始状态 1, 终止状态 5 6 7
节点编号 1~7
1 a 6
1 b 3
2 a 7
2 b 3
3 a 1
3 b 5
4 a 4
4 b 6
5 a 7
5 b 3
6 a 4
6 b 1
7 a 4
7 b 2
0 e 0

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值