编译原理实验 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 
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

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

 

你可能感兴趣的:(编译原理实验 NFA子集法构造DFA,DFA的识别 c++11实现)