编译原理—NFA确定化(C++实现)

原理P51页

重点

  • move操作

    • 不包含本身元素

    • 只传递一次

  • 空闭包closure操作

    • 包含本身元素

    • 无限传递

运行效果 

 项目源码

#include <bits/stdc++.h>
using namespace std;

int m; 

int start = -1;
// 结构体
struct edge {
    int v;
    char c;
};

vector<edge>  e[1005], transferFunction[1005];  // 建图
bool vis[1005]; // 节点是否被访问过

// 单元素*闭包(空-闭包)
void null_closure_one(int u, vector<int> & a) {
    a.push_back(u);
    for (auto p : e[u]) {
        int v = p.v;
        char c = p.c;
        if (c == '*' && !vis[v]) {
            vis[v] = true;
            null_closure_one(v, a);
        }
    }
}

// 数组*闭包(空-闭包)
vector<int> null_closure_mul(vector<int> A) {
    memset(vis, false, sizeof(vis));
    vector<int> ans;
    for (auto x : A) {
        null_closure_one(x, ans);
    }
    sort(ans.begin(), ans.end());
    return ans;
}


// 单元素move
void move_one(int u, char c, vector<int> & a) { 
    for (auto p : e[u]) {
        int v = p.v;
        char cc = p.c;
        if (cc == c && !vis[v]) {
            vis[v] = true;
            a.push_back(v);
        }
    }
}

// 数组move
vector<int> move_mul(vector<int> A, char c) {
    memset(vis, false, sizeof(vis));
    vector<int> ans;
    for (auto x : A) {
        move_one(x, c, ans);
    }
    sort(ans.begin(), ans.end());
    return ans;
}

map<vector<int>, int> done; // 子集是否被访问过
vector<vector<int>> C;  // 子集组

vector<int> T; // 对应课本中的  T0  T1  T2 ...
int cnt = 0; //用来存储T对应的下标,  最后有cnt个子集被标记
set<char> sign; // 记录弧的种类


void print_tips() {
    cout << "* is null "  << endl;
    cout << "how many transfor function ?  (copy follow example):  " << endl;
    cout << "---------------------------" << endl;
    cout << "13" << endl;
    cout << "0 * 1" << endl;
    cout << "0 * 7" << endl;
    cout << "1 * 2" << endl;
    cout << "1 * 4" << endl;
    cout << "2 a 3" << endl;
    cout << "3 * 6" << endl;
    cout << "4 b 5" << endl;
    cout << "5 * 6" << endl;    
    cout << "6 * 1" << endl;
    cout << "6 * 7" << endl;
    cout << "7 a 8" << endl;
    cout << "8 b 9" << endl;
    cout << "9 b 10" << endl;
    cout << "---------------------------" << endl;
}


void read() {
    cin >> m; // 转换函数数量
    for (int i = 1; i <= m; ++i) {
        int u, v; char c; // u:起点 v:终点  c:弧值
        cin >> u >> c >> v;
        e[u].push_back({v, c});
        sign.insert(c);
        if (start == -1) start = u;
    }
    sign.erase('*'); // 记录所有的弧值(去掉空)
}

void print_Ts() {
    cout << "----------------------------------------------" << endl;
    int sz = C.size();
    for (int i = 0; i < sz; ++i) {
        int size = C[i].size();
        cout << "T[" << i << "] = {";
        for (int j = 0; j < size; ++j) {
            printf("%d", C[i][j]);
            if (j < size - 1) cout << " , ";
            if (j == size - 1) cout << "}\n";
            // printf("%d%s", C[i][j], " }\n"[j == size - 1]);
        }
    }
    cout << "----------------------------------------------" << endl;
}

void print_transferFunctions() {
    int sz = C.size();
    // 打印
    for (int i = 0; i < sz; ++i) {
        for (auto p : transferFunction[i]) {
            cout << "      " << p.c << endl;
            cout << "T["<< i <<"]" << " ---> " <<"T[" <<(p.v - 1)<<"]"<< endl;  
        }
    }
    cout << endl;
}


void solve() {
    memset(vis, false, sizeof(vis));
    null_closure_one(start, T);
    C.push_back(T);

    bool ok = true;
    while (ok) { // 试探是否还有没有标记的子集  true代表还有
        ok = false;
        int sz = C.size();
        for (int i = 0; i < sz; ++i) {
            vector<int> Tx = C[i];
            if (!done[Tx]) { // 该子集未被标记过
                ok = true;
                done[Tx] = ++cnt; // 标记
                for (set<char> :: iterator it = sign.begin(); it != sign.end(); it++) {
                    memset(vis, false, sizeof(vis));
                    vector<int> T = null_closure_mul(move_mul(Tx, *it));
                    if (!done[T]) {
                        C.push_back(T);
                        int sz = C.size();
                        transferFunction[i].push_back({sz, *it}); // 编号为i的子集 通过弧*it 转换到子集 sz
                    }
                    else { // 没产生新的子集,也需要记录 转换函数
                        transferFunction[i].push_back({done[T], *it}); // 编号为i的子集 通过弧*it 转换到子集 done[T]
                    }
                }
            }
        }
    }
}

int main() {

    print_tips(); // 打印输入提示

    read(); // 对输入进行处理, 存储边

    solve(); // 进行move 和 空-闭包操作

    print_Ts(); // 打印T集合
    print_transferFunctions(); // 打印确定化后的 转换函数

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xingxg.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值