-
概述
NFA非有窮自動機,即當前狀態識別某個轉換條件后到達的后繼狀態不唯一,這種自動機不便機械實現,而DFA是確定有限狀態的自動機,它的狀態轉換的條件是確定的,且狀態數目往往少於NFA,所以DFA能夠比較方便的機械實現且識別能力方面也和NFA相當。本次實驗采用子集構造法來實現不帶空弧的由NFA到DFA的轉換。
子集構造法的算法如下:
設NFA為M=(K,Σ,f,S0,Z),則構造相應的DFA M′=(Q,Σ,f′,I0,F)
①取I0=S0;
②對於狀態集Q中任一尚未標記的狀態qi={Si1,Si2,…,Sim},Sik∈K,做:
(1) 標記qi;
(2) 對於每個a∈Σ,置
T=f({Si1,Si2,…,Sim},a)
qj=εCLOSURE(T)
(3) 若qj不在Q中,則將qj作為一個未加標記的狀態添加到Q中,且把狀態轉移f′(qi,a)=qj添加到M′。
③重復進行步驟②,直到Q中不再含有未標記的狀態為止。對於由此構造的Q,我們把那些至少含有一個Z中的元素的qi作為M′的終態。
對於如圖所示的NFA其在文件中保存的信息如下
轉成DFA之后的形式為
重命名為
-
程序整體思路
首先將文件中所給的NFA輸入讀入程序,在讀入過程中將其以圖的鄰接表的形式保存,其中將狀態轉移條件記為該邊的權值,每種狀態記為圖的結點,該狀態識別狀態轉移條件(權值)之后到達的狀態為該結點的鄰接點。
對於上面的例子,將其讀入程序中后該圖在程序中的邏輯存儲結構(圖的鄰接表)如圖所示,其中鄰接點中第一個數字表示權值,第二個數字表示所連的結點。
將圖讀入程序中后,再使用子集構造算法來完成由NFA到DFA的轉化。
對於每種狀態,其數據結構定義為

1 typedef struct state 2 { 3 set<int> Set; 4 char name; 5 }state;
其中set里存放該狀態識別某個條件后所能到達的狀態集合的下標,name里存該狀態重命名后的名字。
這些狀態保存在狀態數組States[max]中,狀態數組States[max]數據結構定義為

1 state States[max];
子集構造法的過程就是不斷向狀態數組States[ ]中,添加識別某個條件后,新的未出現的狀態的過程。
程序中函數說明
void creatph(algraph &g,FILE *fpr):將文件內容讀入程序,並將其轉換為圖的鄰接表子函數。
int change(algraph g,char p):將圖中結點轉化為對應下標子函數。
state move(state s,int n,algraph g):求當前狀態集合的轉移集合,即求s狀態識別字母n之后的狀態集合。
int equalSet(state m,state n):比較兩個狀態的set集合內容是否相等,不相等返回0,相等返回1。
void inStates(state &s):判斷當前狀態是否在States數組中存在,若存在,進行改名;若不存在,改名后加入States數組。
void changeToD(algraph g,FILE *fpw):由NFA轉到DFA的主控程序子函數。
程序輸入如下圖所示
程序輸出如下圖所示
-
代碼清單

1 #include<stdio.h> 2 #include<malloc.h> 3 #include <iostream> 4 #include <fstream> 5 #include <cstring> 6 #include<set> 7 8 using namespace std; 9 10 #define max 50//定義結點最大數量 11 typedef char vertype;//定義結點值域為字符類型 12 char buf[1024];//定義讀文件內容時,程序緩沖數組 13 int num;//記錄有窮字母表元素的個數 14 int length;//記錄States數組的長度 15 16 typedef struct arcnode//圖的邊信息 17 { 18 int adjvex; 19 int weight;//邊所對應的權值 20 struct arcnode *next; 21 }arcnode; 22 23 typedef struct vnode//圖的結點類型定義 24 { 25 vertype data; 26 arcnode *next; 27 }vnode,adjlist[max]; 28 29 typedef struct//圖的定義 30 { 31 adjlist a; 32 int vexnum,arcnum; 33 }algraph; 34 35 typedef struct state//狀態的定義 36 { 37 set<int> Set; 38 char name; 39 }state; 40 41 state States[max]; 42 43 int change(algraph g,char p)//將圖中結點轉化為對應下標 44 { 45 int i; 46 for(i=0;i<g.vexnum;i++) 47 { 48 if(p==g.a[i].data) 49 return i; 50 } 51 return -1; 52 } 53 54 void creatph(algraph &g,FILE *fpr) 55 { 56 int line = 0; 57 while(!feof(fpr)) 58 { 59 fgets(buf,1024,fpr); 60 if(strlen(buf)>1)//獲取文件中圖的結點個數 61 { 62 int i = 0; 63 while(buf[i]==' ') 64 { 65 i++; 66 } 67 68 g.a[line].data=buf[i]; 69 g.a[line].next=NULL; 70 line++; 71 } 72 } 73 g.vexnum=line; 74 75 rewind(fpr);//將文件指針返回到開頭位置 76 line = 0; 77 arcnode *s; 78 79 while(!feof(fpr))//再次掃描文件將邊的信息添上,構造圖 80 { 81 int weight=0;//邊所對應的權值,每一行權值都從0開始 82 fgets(buf,1024,fpr); 83 if(strlen(buf)>1) 84 { 85 for(int i=0;i<strlen(buf)-1;i++) 86 { 87 if(buf[i]=='{') 88 { 89 weight++; 90 if(num<weight) 91 num=weight; 92 93 i++; 94 if(buf[i]=='N') 95 i=i+4; 96 97 while(buf[i]!='}') 98 { 99 if(buf[i]!=',') 100 { 101 //cout<<buf[i];//////////////////////////////// 102 int x = change(g,buf[i]); 103 104 s=(arcnode *)malloc(sizeof(arcnode)); 105 s->adjvex=x; 106 s->weight=weight; 107 s->next=g.a[line].next; 108 g.a[line].next=s; 109 //cout<<line;//////////////////////////////// 110 } 111 i++; 112 } 113 } 114 } 115 line++; 116 } 117 } 118 119 } 120 121 state move(state s,int n,algraph g)//求當前狀態集合的轉移集合,即求s狀態識別字母n之后的狀態集合 122 { 123 state temp; 124 arcnode *m; 125 set<int>::iterator itr;//迭代器 126 for(itr = s.Set.begin();itr!=s.Set.end();itr++)//遍歷當前s狀態中集合元素 127 { 128 int i = *itr; 129 m = g.a[i].next; 130 while(m) 131 { 132 if(m->weight==n) 133 { 134 temp.Set.insert(m->adjvex);//cout<<m->adjvex<<" "; 135 // temp.name=s.name+1;//cout<<temp.name<<endl; 136 } 137 m=m->next; 138 } 139 } 140 return temp; 141 } 142 143 int equalSet(state m,state n)//比較兩個狀態的set集合內容是否相等 144 { 145 int flag = 1; 146 if(m.Set.size()!=n.Set.size()) 147 { 148 flag = 0; 149 return flag; 150 } 151 152 set<int>::iterator itrm; 153 set<int>::iterator itrn; 154 for(itrm = m.Set.begin(),itrn = n.Set.begin();itrm!=m.Set.end();itrm++,itrn++) 155 { 156 int m = *itrm; 157 int n = *itrn; 158 159 if(m!=n) 160 { 161 flag = 0; 162 break; 163 } 164 } 165 return flag; 166 } 167 168 void inStates(state &s)//判斷當前狀態是否在States數組中存在,若存在,進行改名;若不存在,改名后加入States數組 169 { 170 int flag = 0; 171 if(length==0) 172 { 173 States[0]=s; 174 States[0].name='A'; 175 length++; 176 } 177 else 178 { 179 for(int i=0;i<length;i++) 180 { 181 //cout<<equalSet(States[i],s); 182 if(equalSet(States[i],s)==1)//若存在,進行改名 183 { 184 s.name=States[i].name; 185 flag = 1; 186 break; 187 } 188 } 189 190 if(flag == 0)//若不存在,改名后加入States數組 191 { 192 s.name=States[length-1].name+1; 193 States[length]=s; 194 length++; 195 } 196 } 197 } 198 199 void changeToD(algraph g,FILE *fpw) 200 { 201 state s,temp; 202 s.Set.insert(0); 203 s.name='A'; 204 205 inStates(s); 206 207 for(int i=0;i<length;i++) 208 { 209 cout<<"{"; 210 fprintf(fpw,"{"); 211 212 set<int>::iterator itr;//迭代器 213 for(itr = States[i].Set.begin();itr!=States[i].Set.end();itr++)//遍歷當前s狀態中集合元素 214 { 215 int i = *itr; 216 cout<<g.a[i].data<<","; 217 fprintf(fpw,"%c,",g.a[i].data); 218 } 219 220 cout<<"}"; 221 fprintf(fpw,"}"); 222 223 cout<<States[i].name; 224 fprintf(fpw,"%c",States[i].name); 225 226 for(int j=1;j<=num;j++) 227 { 228 temp = move(States[i],j,g); 229 inStates(temp); 230 //查看temp狀態的set集合 231 /* 232 set<int>::iterator itr;//迭代器 233 for(itr = temp.Set.begin();itr!=temp.Set.end();itr++)//遍歷當前s狀態中集合元素 234 { 235 int i = *itr; 236 cout<<i<<" "; 237 }*/ 238 cout<<temp.name; 239 fprintf(fpw,"%c",temp.name); 240 } 241 cout<<endl; 242 fprintf(fpw,"\n"); 243 } 244 } 245 246 247 int main() 248 { 249 algraph g; 250 251 FILE *fpr = fopen("F:\\test.txt","r"); 252 FILE *fpw = fopen("F:\\testOutput.txt","w"); 253 254 255 /* FILE *fpr = fopen("test.txt","r"); 256 FILE *fpw = fopen("output.txt","w");*/ 257 258 creatph(g,fpr); 259 260 //create測試 261 /* 262 for(int i=0;i<g.vexnum;i++) 263 { 264 cout<<g.a[i].data<<endl;////////////////// 265 266 } 267 */ 268 269 changeToD(g,fpw); 270 //move測試 271 /* 272 state s; 273 s.Set.insert(0); 274 s.Set.insert(2); 275 s.Set.insert(3); 276 s.mark=1; 277 s.name='B'; 278 279 move(s,2,g); 280 */ 281 return 0; 282 }