日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【C++实现】编译原理 免考小队 NFA转换为等价的DFA

發(fā)布時間:2023/12/8 c/c++ 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++实现】编译原理 免考小队 NFA转换为等价的DFA 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

期末考試免考,沖!

實驗名稱

對任意給定的NFA M進行確定化操作

實驗時間

2020年5月21日 到 2020年5月24日

院系

信息科學(xué)與工程學(xué)院

組員姓名

Chocolate、kry2025、鐘先生、leo、小光

實驗環(huán)境介紹

  • windows 10 操作系統(tǒng)
  • Eclipse 進行 java 編程
  • CodeBlocks 進行 C++ 編程

實驗?zāi)康呐c要求

目的

  • 深刻理解 NFA 確定化操作
  • 掌握子集構(gòu)造算法過程
  • 加強團隊合作能力
  • 提高自身的編程能力和解決問題的能力

要求

NFA 轉(zhuǎn)換為等價的 DFA

正則 到 NFA的轉(zhuǎn)換

有窮自動機

作用:將輸入的序列轉(zhuǎn)換成一個狀態(tài)圖,方便之后的處理。通常被用在詞法分析器中。
1)有窮自動機是一個識別器,對每個可能的的輸入串簡單的回答“是”或“否”。
2)有窮自動機分為兩類:
a)不確定的有窮自動機(NFA)對其邊上的標(biāo)號沒有任何限制。一個符號標(biāo)記離開同一狀態(tài)的多條變,并且空串ε也可以作為標(biāo)號。
b)確定的有窮自動機(DFA)有且只有一條離開該狀態(tài),以該符號位標(biāo)號的邊。

不確定的有窮自動機

正則式(RE)轉(zhuǎn)不確定型有窮自動機(NFA)


找出所有可以被匹配的字符即符號集合∑作為每一列的字段名,然后從起始態(tài)開始
1)狀態(tài)0可以匹配a,匹配后可以到狀態(tài)0或狀態(tài)1,記為?。匹配b只能得到狀態(tài)0,記為{0}。
2)狀態(tài)1可以匹配a,沒有匹配到,記為?。匹配b得到狀態(tài)2,記為{2}。
3)狀態(tài)0可以匹配a,沒有匹配到,記為?。匹配b得到狀態(tài)3,記為{3}。
4)狀態(tài)0可以匹配a,沒有匹配到,記為?。匹配b沒有匹配到,記為?。

至此,狀態(tài)表建立完成。正則式(RE)轉(zhuǎn)不確定型有窮自動機(NFA)完成。

NFA 到 DFA

NFA M 確定化

1)根據(jù)NFA構(gòu)造DFA狀態(tài)轉(zhuǎn)換矩陣:

  • ①確定DFA的字母表,初態(tài)(NFA的所有初態(tài)集)
  • ②從初態(tài)出發(fā),經(jīng)字母表到達的狀態(tài)集看成一個新狀態(tài)
  • ③將新狀態(tài)添加到DFA狀態(tài)集
  • ④重復(fù)②③步驟,直到?jīng)]有新的DFA狀態(tài)

2)畫出DFA

3)看NFA和DFA識別的符號串是否一致

NFA N 確定化

涉及操作:

算法:

更多詳細內(nèi)容可參考:NFA到DFA的轉(zhuǎn)換及DFA的簡化

實驗過程

對NFA M 確定化

采用二進制方法來對NFA M 進行確定化,先來說說其中用到的關(guān)鍵知識:

將狀態(tài)集合用二進制表示,例如,如果一個集合(從0開始)包含了 0,1,2,總共有4個狀態(tài)(即 0,1,2,3 ),那么,當(dāng)前集合用 0111 表示。同理,如果包含了0,3 ,總共有4個狀態(tài)(即 0,1,2,3 ),那么,當(dāng)前集合用 1001 表示。

x & (-x) 表示拿到 x 的最右邊第一個

a & x 可以判斷 a 狀態(tài)集合 是否包含 x 狀態(tài)集合

a ^= x 可以用來將 x 狀態(tài)集合 加入到 a 狀態(tài)集合

下面依次來講述代碼實現(xiàn):

int ans[maxn],one[maxn],zero[maxn],lft[maxn],rgt[maxn]; char change[maxn]; bool vis[maxn],ac[maxn];

用到的數(shù)據(jù)結(jié)構(gòu):

  • ans 數(shù)組表示所求的狀態(tài)集合
  • one 數(shù)組表示狀態(tài)經(jīng) 1 所到達的狀態(tài)
  • zero 數(shù)組表示狀態(tài)經(jīng) 0 所到達的狀態(tài)
  • lft 數(shù)組表示經(jīng)過 0 狀態(tài)到達的狀態(tài)集合
  • rgt 數(shù)組表示經(jīng)過 1 狀態(tài)到達的狀態(tài)集合
  • change 數(shù)組用來轉(zhuǎn)換輸出結(jié)果,即將狀態(tài)集合用字母 ‘A’-‘Z’ 來表示
  • vis 數(shù)組用來去重操作,判斷當(dāng)前狀態(tài)集合是否存在過
  • ac 數(shù)組用來判斷集合狀態(tài)中是否包含終態(tài),若包含,置為1

下面函數(shù)是用來找到對應(yīng)狀態(tài)下標(biāo)

//找到對應(yīng)的狀態(tài)下標(biāo) int index(int p){int x = 1;if(p == 1) //p為1表示當(dāng)前為初始狀態(tài)return 0;int i = 0;while(++i){ //循環(huán)找出當(dāng)前對應(yīng)的狀態(tài)下標(biāo)x <<= 1;if(p == x)return i; //找到即返回對應(yīng)下標(biāo)}return 0; }

move操作

int moveT(int a, int b){while(b){int x = b&(-b); //去當(dāng)前集合中的最后一個節(jié)點if(!(a&x)) //如果不存在該節(jié)點,加入集合當(dāng)中a ^= x;b ^= x; //已經(jīng)存在該節(jié)點,就進行舍去操作}return a; }

核心代碼,將狀態(tài)集合逐個拿出來,進行 move 操作,然后進行去重操作,最后進行更新新的狀態(tài)集合

void dfs(int p){ans[cnt] = p;int lsum = 0, rsum = 0;while(p){int x = p&(-p); //取出當(dāng)前集合中的最后一個節(jié)點int y = index(x); //找到對應(yīng)的狀態(tài)下標(biāo)lsum = moveT(lsum, zero[y]); //進行move操作rsum = moveT(rsum, one[y]); //進行move操作p ^= x; //將當(dāng)前拿出來的節(jié)點從原集合中去掉}lft[cnt] = lsum; //更新當(dāng)前的狀態(tài)集合rgt[cnt] = rsum; //更新當(dāng)前的狀態(tài)集合cnt++; //更新狀態(tài)行數(shù)if(!vis[lsum])vis[lsum] = 1, dfs(lsum); //進行去重操作if(!vis[rsum])vis[rsum] = 1, dfs(rsum); //進行去重操作 }

輸入處理

while(cin>>preNode){if(preNode=='$') break;cin>>tchar>>nexNode;if(tchar-'a'==0) zero[preNode-'0']|=(1<<(nexNode-'0'));else one[preNode-'0']|=(1<<(nexNode-'0')); }

輸出處理

for(int i=0;i<cnt;i++)change[ans[i]]=i+'A'; //輸出處理,用字母'A'-'Z'來表示集合

對NFA N 確定化

用到的數(shù)據(jù)結(jié)構(gòu):

struct edge{char preNode; //前驅(qū)節(jié)點char tchar; //弧char nexNode; //后繼節(jié)點 }e[maxn]; //獲得的狀態(tài)集合 struct newJ{string setJ; }; //集合與集合之間的轉(zhuǎn)換關(guān)系 struct relation{newJ* preJ;char jchar;newJ* nexJ; };
  • edge 結(jié)構(gòu)體用來表示邊的信息
  • newJ 表示狀態(tài)集合J
  • relation 結(jié)構(gòu)體表示最后輸出的轉(zhuǎn)換關(guān)系表

求某個狀態(tài)的閉包

//得到閉包 void getEClosure(const edge* e,int cntEdge,newJ* st){for(int i=0;i<st->setJ.length();i++){for(int j=0;j<cntEdge;j++){ //遍歷所有的邊if(st->setJ[i] == e[j].preNode && e[j].tchar=='#')st->setJ+=e[j].nexNode;}} }

move操作

//move操作 void moveT(char ttchar,const edge* e,int cntEdge,newJ* source,newJ* dest){//e為所有邊的集合,然后就能從一個轉(zhuǎn)換字符得到全部的,比如2得到bd,而不會第一個2得到b,第二個2得到dfor(int i=0;i<source->setJ.length();i++){for(int j=0;j<cntEdge;j++){ //遍歷所有的邊if(source->setJ[i] == e[j].preNode && e[j].tchar == ttchar)dest->setJ+=e[j].nexNode;}} }

去重操作,判斷是否加入 allSet(總狀態(tài)集合) 中

//通過狀態(tài)集合中的setJ來決定是否添加 bool isInsert(vector<newJ*> allSet,newJ* newSet){for(int i=0;i<allSet.size();i++){if(allSet.at(i)->setJ == newSet->setJ)return false;}return true; }

去重操作,判斷當(dāng)前狀態(tài)轉(zhuǎn)換是否加入轉(zhuǎn)換關(guān)系表中

//判斷relation結(jié)構(gòu)體去重 bool isInsertForRel(vector<relation*> relVec,newJ* preJ,char jchar,newJ* nexJ){for(int i=0;i<relVec.size();i++){if(relVec.at(i)->preJ->setJ == preJ->setJ && relVec.at(i)->jchar == jchar && relVec.at(i)->nexJ->setJ == nexJ->setJ)return false;}return true; }

重命名轉(zhuǎn)換函數(shù)

//重命名轉(zhuǎn)換函數(shù) void changeName(vector<newJ*> allSet,newJ* newSet,string& newStr){newJ* tmpJ = new newJ();for(int i=0;i<allSet.size();i++){if(allSet.at(i)->setJ == newSet->setJ)tmpJ->setJ = 'A'+i;}newStr = tmpJ->setJ; }

后續(xù)省略…(詳情請見后文源代碼說明)

實驗結(jié)果(附源代碼)

對 NFA M 確定化

#include<bits/stdc++.h> #define endl '\n' using namespace std; const int maxn=999999; int ans[maxn],one[maxn],zero[maxn],lft[maxn],rgt[maxn]; char change[maxn]; bool vis[maxn],ac[maxn]; int cnt,n,q,f; //找到對應(yīng)的狀態(tài)下標(biāo) int index(int p){int x = 1;if(p == 1) //p為1表示當(dāng)前為初始狀態(tài)return 0;int i = 0;while(++i){ //循環(huán)找出當(dāng)前對應(yīng)的狀態(tài)下標(biāo)x <<= 1;if(p == x)return i; //找到即返回對應(yīng)下標(biāo)}return 0; } int moveT(int a, int b){while(b){int x = b&(-b); //去當(dāng)前集合中的最后一個節(jié)點if(!(a&x)) //如果不存在該節(jié)點,加入集合當(dāng)中a ^= x;b ^= x; //已經(jīng)存在該節(jié)點,就進行舍去操作}return a; } void dfs(int p){ans[cnt] = p;int lsum = 0, rsum = 0;while(p){int x = p&(-p); //取出當(dāng)前集合中的最后一個節(jié)點int y = index(x); //找到對應(yīng)的狀態(tài)下標(biāo)lsum = moveT(lsum, zero[y]); //進行move操作rsum = moveT(rsum, one[y]); //進行move操作p ^= x; //將當(dāng)前拿出來的節(jié)點從原集合中去掉}lft[cnt] = lsum; //更新當(dāng)前的狀態(tài)集合rgt[cnt] = rsum; //更新當(dāng)前的狀態(tài)集合cnt++; //更新狀態(tài)行數(shù)if(!vis[lsum])vis[lsum] = 1, dfs(lsum); //進行重復(fù)操作if(!vis[rsum])vis[rsum] = 1, dfs(rsum); //進行重復(fù)操作 } int main(){int t;cout<<"多組輸入,請先輸入對應(yīng)的組數(shù):"<<endl;cin>>t; //多組輸入while(t--){cout << "輸入各邊的信息,并且以 '前點(char '0'-'1000') 轉(zhuǎn)換字符(a 或 b) 后點(int '0'-'1000')'格式,結(jié)束以'$'開頭" << endl;char preNode,tchar,nexNode;while(cin>>preNode){if(preNode=='$') break;cin>>tchar>>nexNode;if(tchar-'a'==0) zero[preNode-'0']|=(1<<(nexNode-'0'));else one[preNode-'0']|=(1<<(nexNode-'0'));}q=1;cout<<"輸入終止?fàn)顟B(tài)集合,結(jié)束以'$'開頭"<<endl;char endNode;while(cin>>endNode){if(endNode=='$') break;f|=(1<<(endNode-'0'));}cnt=0;memset(vis,0,sizeof(vis)); //初始化memset(ac,0,sizeof(ac)); //初始化vis[q]=1;dfs(q); //轉(zhuǎn)換開始int sum=0;for(int i=0;i<cnt;i++)if(ans[i]&f) //判斷所求集合中是否包含終態(tài)ac[i]=1,sum++; //標(biāo)記終態(tài)集合并統(tǒng)計個數(shù)for(int i=0;i<cnt;i++)change[ans[i]]=i+'A'; //輸出處理,用字母'A'-'Z'來表示集合cout<<"轉(zhuǎn)換結(jié)果:"<<endl;cout<<"DFA的狀態(tài)數(shù):"<<cnt<<" "<<"終止?fàn)顟B(tài)數(shù):"<<sum<<endl<<endl;cout<<"終態(tài):"<<endl; //輸出終態(tài)集合for(int i=0,j=0;i<cnt;i++){if(ac[i]){if(j)cout<<" ";cout<<(char)(i+'A');j++;}}cout<<endl<<endl; //輸出DFA狀態(tài)轉(zhuǎn)換矩陣cout<<"由NFA得到的DFA狀態(tài)轉(zhuǎn)換矩陣:"<<endl;cout<<"----------------------------"<<endl;cout<<" "<<"a"<<" "<<"b"<<endl;cout<<"----------------------------"<<endl;for(int i=0;i<cnt;i++) //輸出打印新的轉(zhuǎn)換結(jié)果cout<<(char)('A'+i)<<" "<<change[lft[i]]<<" "<<change[rgt[i]]<<endl;cout<<"----------------------------"<<endl;cout<<endl;}return 0; }

輸出結(jié)果

輸出結(jié)果文字版

多組輸入,請先輸入對應(yīng)的組數(shù): 100 輸入各邊的信息,并且以 '前點(char '0'-'1000') 轉(zhuǎn)換字符(a 或 b) 后點(int '0'-'1000')'格式,結(jié)束以'$'開頭 0 b 2 4 a 0 0 a 1 1 a 1 2 b 3 3 b 2 3 a 3 5 a 5 4 b 5 5 b 4 1 b 4 2 a 1 $ 輸入終止?fàn)顟B(tài)集合,結(jié)束以'$'開頭 0 $ 轉(zhuǎn)換結(jié)果: DFA的狀態(tài)數(shù):6 終止?fàn)顟B(tài)數(shù):1終態(tài): A由NFA得到的DFA狀態(tài)轉(zhuǎn)換矩陣: ----------------------------a b ---------------------------- A B E B B C C A D D D C E B F F F E ----------------------------

對NFA N 確定化

#include<bits/stdc++.h> using namespace std; const int maxn=1000; struct edge{char preNode; //前驅(qū)節(jié)點char tchar; //弧char nexNode; //后繼節(jié)點 }e[maxn]; //獲得的狀態(tài)集合 struct newJ{string setJ; }; //集合與集合之間的轉(zhuǎn)換關(guān)系 struct relation{newJ* preJ;char jchar;newJ* nexJ; }; //得到閉包 void getEClosure(const edge* e,int cntEdge,newJ* st){for(int i=0;i<st->setJ.length();i++){for(int j=0;j<cntEdge;j++){ //遍歷所有的邊if(st->setJ[i] == e[j].preNode && e[j].tchar=='#')st->setJ+=e[j].nexNode;}} } //move操作 void moveT(char ttchar,const edge* e,int cntEdge,newJ* source,newJ* dest){//e為所有邊的集合,然后就能從一個轉(zhuǎn)換字符得到全部的,比如2得到bd,而不會第一個2得到b,第二個2得到dfor(int i=0;i<source->setJ.length();i++){for(int j=0;j<cntEdge;j++){ //遍歷所有的邊if(source->setJ[i] == e[j].preNode && e[j].tchar == ttchar)dest->setJ+=e[j].nexNode;}} } //通過狀態(tài)集合中的setJ來決定是否添加 bool isInsert(vector<newJ*> allSet,newJ* newSet){for(int i=0;i<allSet.size();i++){if(allSet.at(i)->setJ == newSet->setJ)return false;}return true; } //判斷relation結(jié)構(gòu)體去重 bool isInsertForRel(vector<relation*> relVec,newJ* preJ,char jchar,newJ* nexJ){for(int i=0;i<relVec.size();i++){if(relVec.at(i)->preJ->setJ == preJ->setJ && relVec.at(i)->jchar == jchar && relVec.at(i)->nexJ->setJ == nexJ->setJ)return false;}return true; } //重命名轉(zhuǎn)換函數(shù) void changeName(vector<newJ*> allSet,newJ* newSet,string& newStr){newJ* tmpJ = new newJ();for(int i=0;i<allSet.size();i++){if(allSet.at(i)->setJ == newSet->setJ)tmpJ->setJ = 'A'+i;}newStr = tmpJ->setJ; } int main(){int cntEdge=0; //統(tǒng)計邊的數(shù)量char staNode; //初始狀態(tài)點string endNode,node; //終止?fàn)顟B(tài)節(jié)點和總的節(jié)點集合int cntRealEdge[maxn]={0}; //用于判斷是否包含空字符的邊 為1代表含空字符的邊 初始話為0,不包含cout << "輸入各邊的信息,并且以 '前點(char '0'-'1000') 轉(zhuǎn)換字符(char 'a'-'z') 后點(char '0'-'1000')'格式,結(jié)束以'$'開頭" << endl;cout << "如果轉(zhuǎn)換字符為空,則用'#'表示" << endl;char ttchar[2];for(int i=0;i<maxn;i++){cin>>e[i].preNode; //輸入前點if(e[i].preNode == '$') break; //遇到'$' 結(jié)束輸入cin>>ttchar;cin>>e[i].nexNode; //輸入轉(zhuǎn)換字符及后點e[i].tchar=ttchar[0];if(ttchar[0] == '#') cntRealEdge[cntEdge]=1; //標(biāo)記含有空字符的邊++cntEdge; //統(tǒng)計邊的數(shù)量}//將輸入的邊節(jié)點進行整合for(int i=0;i<cntEdge;i++){char preTmp = e[i].preNode;char nexTmp = e[i].nexNode;if(node.find(preTmp)>node.length()) node+=preTmp;if(node.find(nexTmp)>node.length()) node+=nexTmp;}cout<<"輸入初始點字符:"<<endl;cin>>staNode;while(node.find(staNode)==string::npos){cout<<"初始狀態(tài)輸入錯誤,請重新輸入:"<<endl;cin>>staNode; //錯誤即重新輸入一次}cout<<"輸入終止點字符(若有多個終結(jié)狀態(tài),直接寫成字符串形式)"<<endl;cin>>endNode;bool inputStatus=true; //用于結(jié)束終止點字符的輸入while(inputStatus){for(int i=0;i<endNode.length();i++){if(node.find(endNode[i])==string::npos){cout << "終結(jié)狀態(tài)輸入錯誤,請重新輸入:" << endl;cin >> endNode;}}inputStatus=false;}newJ* newSet = new newJ();newSet->setJ = staNode; //設(shè)置初始點為狀態(tài)集合IgetEClosure(e, cntEdge, newSet); //得到閉包vector<newJ*>allSet(1, newSet); //設(shè)置所有狀態(tài)集合的向量/*用來存儲每一次的閉包操作前的第一列的狀態(tài)集合*比如第一次strVec存儲的是初始狀態(tài),求閉包時多了2個狀態(tài)集合。在第二次時存儲的是新的2個狀態(tài),原先的初始狀態(tài)被去除。*總的狀態(tài)集合存儲在allSet中*/vector<newJ*>strVec(1, newSet);int sizeOfStrVec = 1; //初始大小就是初始點所構(gòu)成的狀態(tài)集合vector<relation*>relVec; //轉(zhuǎn)換關(guān)系表的向量while(sizeOfStrVec){ //如果不符合則說明新增的集合都是原有的集合int oldAllSize=allSet.size(); //求出目前存儲的狀態(tài)集合大小for(int j=0;j<sizeOfStrVec;j++){for(int i=0;i<cntEdge;i++){newJ* dest=new newJ();if(!cntRealEdge[i]){ //不是空字符邊的,對它進行move操作moveT(e[i].tchar, e, cntEdge, strVec.at(j), dest);//如果有一個字符在多條邊上,所以要按字符相同的歸類集合。否則就會使得狀態(tài)集合分開而造成錯誤!!getEClosure(e, cntEdge, dest); //此時dest為 Ia,Ib之類的if(isInsert(allSet,dest) && dest->setJ!="") //沒找到并且dest->setJ且不為空則添加allSet.push_back(dest);//在添加relVec時,只要是不為空就要添加,這里會使relDest的元素可能重復(fù)(當(dāng)一個字符出現(xiàn)在多條邊中)if (dest->setJ != ""){relation* relDest = new relation();relDest->preJ = strVec.at(j);relDest->jchar = e[i].tchar;relDest->nexJ = dest;bool isIN = isInsertForRel(relVec,relDest->preJ,relDest->jchar,relDest->nexJ); //去重if(isIN) relVec.push_back(relDest);}}}}strVec.clear(); //去除原狀態(tài)集合for(int i=oldAllSize;i<allSet.size();i++){//將allSet中新增的后面元素添加進strVec中newJ* dest = new newJ();dest = allSet.at(i);strVec.push_back(dest);}sizeOfStrVec = strVec.size(); //求出目前存儲的狀態(tài)集合大小}cout << "轉(zhuǎn)換結(jié)果:" << endl;vector<relation*>::iterator relIt;for(relIt=relVec.begin();relIt!=relVec.end();relIt++) //遍歷輸出關(guān)系轉(zhuǎn)換表的集合cout<<(*relIt)->preJ->setJ<<" "<<(*relIt)->jchar<<" "<<(*relIt)->nexJ->setJ<<endl;char upperChars[26];memset(upperChars,0,sizeof(upperChars));cout<<"重命名如下:"<<endl;for(int i=0;i<allSet.size();i++){upperChars[i] = 'A'+i; //通過下標(biāo)將每一個集合依次從'A'開始 命名cout<<upperChars[i]<<":"<<allSet.at(i)->setJ<<endl;}vector<relation*> newRelVec; //重命名后的relVec;for(int i=0;i<relVec.size();i++){relation* newRel = new relation(); //依次更換新的名稱string preNew,nexNew;changeName(allSet,relVec.at(i)->preJ,preNew);changeName(allSet,relVec.at(i)->nexJ,nexNew);newJ* tpreJ = new newJ();newJ* tnexJ = new newJ();newRel->preJ = tpreJ;newRel->nexJ = tnexJ;newRel->preJ->setJ = preNew;newRel->nexJ->setJ = nexNew;newRel->jchar = relVec.at(i)->jchar;newRelVec.push_back(newRel);}//輸出驗證重命名的集合關(guān)系cout << "最終轉(zhuǎn)換:" << endl;vector<relation*>::iterator newRelIt;for(newRelIt = newRelVec.begin();newRelIt!=newRelVec.end();newRelIt++) //遍歷輸出新的關(guān)系轉(zhuǎn)換表的集合cout<<(*newRelIt)->preJ->setJ<<" "<<(*newRelIt)->jchar<<" "<<(*newRelIt)->nexJ->setJ<<endl;//輸出終止?fàn)顟B(tài)cout<<"終態(tài):"<<endl;set<char> st; //通過set來進行去重操作set<char>::iterator it;for(int k=0;k<allSet.size();k++){for(int i=0;i<endNode.size();i++){if(allSet.at(k)->setJ.find(endNode[i]) != string::npos) //確保終態(tài)在集合中存在st.insert('A'+k); //放入set集合中,達到去重效果}}for(it=st.begin();it!=st.end();it++) cout<<(*it)<<" "; //遍歷輸出終態(tài)集合cout<<endl;return 0; }

輸出結(jié)果

輸出結(jié)果文字版

輸入各邊的信息,并且以 '前點(char '0'-'1000') 轉(zhuǎn)換字符(char 'a'-'z') 后點(char '0'-'1000')'格式,結(jié)束以'$'開頭 如果轉(zhuǎn)換字符為空,則用'#'表示 a 1 b b 1 b b 2 b b # e a # c c 1 c c 2 c c 1 d $ 輸入初始點字符: a 輸入終止點字符(若有多個終結(jié)狀態(tài),直接寫成字符串形式) ed 轉(zhuǎn)換結(jié)果: ac 1 bcde ac 2 c bcde 1 bcde bcde 2 bce c 1 cd c 2 c bce 1 bcde bce 2 bce cd 1 cd cd 2 c 重命名如下: A:ac B:bcde C:c D:bce E:cd 最終轉(zhuǎn)換: A 1 B A 2 C B 1 B B 2 D C 1 E C 2 C D 1 B D 2 D E 1 E E 2 C 終態(tài): B D E

參考文獻

感謝以下博主的文章,本文參考了部分代碼和知識。

Hungryof:NFA到DFA的轉(zhuǎn)換

zhen12321:編譯原理-(NFA->DFA)

發(fā)芽ing的小啊嗚:【20200319】編譯原理課程課業(yè)打卡九之NFA的確定化

Just-Live:湖大OJ-實驗C----NFA轉(zhuǎn)換為DFA

愛玩游戲的小隱:正則到NFA的轉(zhuǎn)換

愛玩游戲的小隱:NFA到DFA的轉(zhuǎn)換及DFA的簡化

學(xué)如逆水行舟,不進則退

總結(jié)

以上是生活随笔為你收集整理的【C++实现】编译原理 免考小队 NFA转换为等价的DFA的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。