• 编译原理实验 NFA子集法构造DFA,DFA的识别 c++11实现


    实验内容

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

    实验步骤

      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 + 10;
    const int prime = 31;
    const ll mod = 1e9 + 7;
    int getHash(const set<int> &s)
    {
        ll res = 0;
        for (auto x : s)
            res = res * prime + x;
        return res % mod;
    }
    struct FA
    {
        int debug = 0;
        char ep = '*';
        set<char> chs;
        int cnt = 0; //最大状态数
        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 = 0; i < m; i++)
            {
                int s, t;
                char ch;
                in >> s >> t >> ch;
                addState(s, t, ch);
            }
            in >> m; //终止状态数目
            for (int i = 0; i < m; i++)
            {
                int st;
                in >> st;
                end_state.emplace(st);
            }
            if (debug)
                cout << "done.
    ";
        }
        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 = 0; 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(0);
            set<int> cur = bfs(st, ep); //初态计算,同时之后的st也代表了计算出来的状态
            mp[0] = cur;                //初态hash值为0不用计算
            queue<int> q;
            st.clear();
            q.emplace(0);
            mp2[0] = 0;
            int num = 1; //状态数目
            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 = 0; 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 << "
    ";
                        for (auto x : mp[mp2[cur]])
                            cout << x << " ";
                        cout << "
    ";
                        for (auto x : mp[mp2[ha]])
                            cout << x << " ";
                        cout << "
    ";
                    }
                    res.addState(mp2[cur], mp2[ha], ch);
                }
            }
            for (int x = 0; x < num; x++)
            {
                set<int> tmp = mp[x];
                int f = 0;
                for (auto y : end_state)
                    if (tmp.count(y))
                    {
                        f = 1;
                        break;
                    }
                if (f)
                    res.addEndState(x);
            }
            return res;
        }
        int isok(string to)
        {
            int len = to.size();
            int st = 0;
            for (int i = 0; i < len; i++)
            {
                char ch = to[i];
                int sz = move[st].size();
                int f = 0;
                for (int j = 0; j < sz && !f; j++)
                {
                    P tmp = move[st][j];
                    if (tmp.second == ch)
                    {
                        f = 1;
                        st = tmp.first;
                    }
                }
                if (!f)
                    break;
            }
            return end_state.count(st);
        }
        void diplayEnd()
        {
            for (auto x : end_state)
                cout << x << " ";
            cout << "
    ";
        }
    } NFA, DFA;
    int main()
    {
        NFA.init("prj2_5.txt");
        DFA = NFA.getDFA();
        cout << "Please enter matching sequence:
    ";
        string to;
    
        while (cin >> to && to != "#")
        {
            cout << (DFA.isok(to) ? "OK" : "NO") << "
    ";
        }
        return 0;
    }
    View Code
  • 相关阅读:
    解释JUNIT中@BEFORECLASS和@AFTERCLASS标注的方法必须是STATIC的,而在TESTNG不必
    XXL开源社区
    java中的IO整理
    Spring MVC 原理探秘
    Servlet一次乱码排查后的总结
    正则表达式简明参考
    牛皮博客
    【转】线程安全的单例模式
    springboot下载excel(解决文件损坏问题)
    JZOJ-TGB817-SOL
  • 原文地址:https://www.cnblogs.com/mooleetzi/p/11817974.html
Copyright © 2020-2023  润新知