學習和掌握將nfa轉為dfa的子集構造法。
(1)儲存nfa與dfa;
(2)程式設計實現子集構造法將nfa轉換成dfa。
(1)確定nfa與dfa的儲存格式。要求為3個以上測試nfa準備好相應有限自動機的儲存檔案。(可利用實驗一(二)的基礎)
(2)用c或c++語言編寫將nfa轉換成dfa的子集構造法的程式。
(3)測試驗證程式的正確性。
測試不易。可求出nfa與dfa的語言集合的某個子集(如長度小於某個n),再證實兩個語言集合完全相同!
(4)測試用例參考:將下列語言用re表示,再轉換成nfa使用:
(a) 以a開頭和結尾的小字字母串;a (a|b|…|z)*a | a
(b) 不包含三個連續的b的,由字母a與b組成的字串;(e | b | bb) (a | ab | abb)*
(c) (aa|b)*(a|bb)*
學會程式設計實現等價劃分法最小化dfa。
先完善dfa,再最小化dfa。
(2)用c或c++語言編寫用等價劃分法最小化dfa的程式。
(3)經測試無誤。測試不易。可求出兩個dfa的語言集合的某個子集(如長度小於某個n),再證實兩個語言集合完全相同!
2 // 字符集中的字元個數 (以下兩行也可合併成一行)
a b // 以空格分隔的字符集。
4 // 狀態個數 (以下兩行也可合併成一行)
1 2 3 4 // 狀態編號。若約定總是用從1開始的連續數字表示,則此行可省略
1 // 開始狀態的編號。若約定為1,則此行可省略
1 // 結束狀態個數。若約定為1,則此行可省略
3 // 結束狀態的編號
3 2 1 // 狀態1的所有出去的轉換。按字符集中的字元順序給出,並在最左邊加上一列關於e的轉換。-1表示出錯狀態。若下乙個狀態有多個時,多個狀態用逗號分隔。
-1 1 -1
-1 3 4
-1 -1 3
使用示性函式。也即:
含有單個狀態的狀態集合用2的冪次表示。即狀態1 ~ n分別用數21 ~ 2n 表示。
含有多個狀態的狀態集合也用數來表示。若兩個狀態集合a與b用數表示為m和n,則狀態集合aèb與açb的數可用「位運算」表示,分別為m|n和m&n。
若想知道某個狀態集合a(用數m表示)中是否包含原先的第i個狀態,也可使用基於「位運算」來判斷:若(m | 2i )> 0,則包含,否則不包含。
實驗通過測試後,按規定時間上交源**、測試樣例、輸出檔案(如有輸出檔案)和電子版實驗報告。
#include#include#include#include#include#include#include#include#define maxn 101
using namespace std;
bool visited[maxn]; //圖演算法遍歷節點用,表示該節點是否被訪問過;
int end_state[maxn]; //終止狀態集合
int state_num,trans_num,end_state_num; //狀態的數量,轉換弧的數量,終止狀態集的狀態個數
char trans_table[maxn][maxn]; //狀態轉換表
string letters; //合法字符集
string letters_null; //合法字符集加上乙個空串
vector> ziji; //構造的子集
map,int> flag; //子集是否被標記過
map> > nfa; //用於存放nfa
settemp; //用於主函式臨時變數
char alpha[26]=; //用於給dfa狀態命名
int hebing=0;
setnfa_ok;
setdfa_ok;
setmin_ok; //存放符合條件的字串
struct dfa_build
;vectordfa;
struct dfa_state //新dfa的狀態名稱,是否為終結狀態
;vectordfa_states; //宣告兩個vector,乙個用於處理nfa轉dfa,乙個用於處理最簡dfa
vectordfa_min;
bool find_re(settmp) //查詢乙個子集是否存在於已有的子集集合中,以免構造狀態重複
return false;
}int finish() //查詢當前的子集擴充套件是否完畢,如子集被擴充套件會被標記,如有子集未標記則接著擴充套件它,返回它的下標,否則返回-1
} return ext; //返回這個擴充套件出的新集合
}sete_closure(setlast) //擴充套件演算法
while(!q.empty()) //佇列每次彈出首位,並以首位進行擴充套件
cout<<"}";
for(int x=0;x::iterator j=tp.begin();j!=tp.end();j++)
}} cout<'z'))
trans_table[i][j]='?';
if(i==0 && j==0)
cout<<'\t';
else
cout<=1 && j>=1)
} coutreturn;
if(nfaok(cur_state))
nfa_ok.insert(tmp1);
for(int i=0;in)
return;
if(dfaok(cur_state))
dfa_ok.insert(tmp2);
for(int i=0;in)
return;
if(minok(cur_state))
min_ok.insert(t***);
for(int i=0;i>state_num;
state_num++;
cout<<"請輸入字符集,不要空格:";
cin>>letters;
letters_null=letters+'*';
cout<<"請輸入終止狀態集的集合數量(已經預設開始狀態為0):";
cin>>end_state_num;
cout<<"請輸入終止狀態集合中的所有狀態:";
for(int i=0;i>end_state[i];
cout<<"請輸入乙個整數n,求長度小於等於n的所有符合條件字串:";
cin>>less_than;
cout<<"請輸入nfa轉換法則,格式(1 a 2,*為空),ctrl+z結束:";
while(cin>>st>>trans>>ed)
nfa[st][trans][ed]=1;
ff.close();
temp.insert(0);
temp=e_closure(temp);
ziji.push_back(temp);
while(1)
cout
cout
cout
cout<<"一共有以下"
searchdfa('a',less_than,0);
cout<<"一共有以下"
searchmin('a',less_than,0);
cout<<"一共有以下"
return 0;
}
/*樣例一:開始就是結束 1a
1030 a 0
*/ /*樣例二:編譯原理習題3.7.3(4)
17ab117
60 * 1
1 * 2
2 a 3
3 * 6
1 * 4
4 b 5
5 * 6
6 * 1
0 * 7
6 * 7
7 a 8
8 b 9
9 b 10
10 * 11
10 * 17
11 * 12
11 * 14
12 a 13
14 b 15
15 * 16
13 * 16
16 * 11
16 * 17
*//*樣例三:實驗三文件 4ab
1240 a 1
1 a 0
0 b 0
0 * 2
2 a 2
2 b 3
3 b 2
*/
編譯原理NFA確定化
1,實驗名稱 不確定有窮自動機的確定化。2,實驗目的 不確定有窮自動機的確定化。3,實驗原理 1.nfa 乙個不確定的有窮自動機m是乙個五元組,m k,e,f,s,z 其中 a.k是乙個有窮集,它的每個元素稱為乙個狀態 b.e是乙個有窮字母表,它的每個元素稱為乙個輸入符號 c.f是乙個從k e 到k...
編譯原理 非確定的自動機NFA確定化為DFA
1.設有 nfa m f,0,其中 f 0,a f 0,b f 1,b f 2,b 畫出狀態轉換矩陣,狀態轉換圖,並說明該nfa識別的是什麼樣的語言。解析 ab 0012 233狀態轉換圖如下 識別語言為 a b abb 2.nfa 確定化為 dfa1.解決多值對映 子集法 1 上述練習1的nfa ...
編譯原理實驗 將NFA轉化為DFA
將nfa轉化為dfa 1.實驗目的 輸入 非確定有限 窮 狀態自動機。輸出 確定化的有限 窮 狀態自動機 2.實驗原理 採用子集對nfa轉dfa。1 若nfa的全部初態為s1,s2,sn,則令dfa的初態為 s s1,s2,sn 其中方括號用來表示若干個狀態構成的某一狀態。2 設dfa的狀態集k中有...