編譯原理實驗 NFA子集法構造DFA,DFA的識別 c++11實現

實驗內容

  將非肯定性有限狀態自動機經過子集法構造肯定性有限狀態自動機。c++

實驗步驟

  1,讀入NFA狀態。注意最後須要設置終止狀態。ide

  2,初始態取空,構造DFA的l0狀態,將l0加入未標記狀態隊列quespa

  3,當que不爲空,取出一個狀態依次作轉移和取空操做,並構造出當前轉移狀態tmp。debug

  4,如tmp是一個新狀態,加入到隊列中。c++11

  5,將構造出的DFA用做模式識別。code

具體實現

  1,文件讀入NFA狀態轉換圖,採用vector存儲。blog

  2,判斷狀態tmp是不是一個新的狀態使用自定義hash方法。隊列

  3,取空操做因爲能夠轉移多步空字符,採用BFS實現。ip

  4,源代碼編譯環境MinGW GCC 8.2.0,c++11,低於c++11的版本不兼容。ci

  

#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
相關文章
相關標籤/搜索