编译原理实验 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.\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 = 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 << "\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 = 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 << "\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 0;
}
View Code

 

posted @ 2019-11-08 08:39  mool  阅读(1279)  评论(0编辑  收藏  举报