編譯原理實驗三 NFA確定化和DFA最小化

2021-09-10 08:56:11 字數 4306 閱讀 3674

學習和掌握將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中有...