dfa最小化,上一个版本采用的是moore的打表法,这个版本采用的是hopcroft的方法,但是实现中采用链表而不是栈来优化。

hopcroft法的复杂度,他们说是nlogn,可是都没有严格的证明。难得找到一篇讲的详细点的论文,却又啰里啰唆的,不过那篇论文里面采用的是颜色树这个结构,有点意思。

前面的那个算法是n的平方复杂度,虽然这个复杂度计算都是建立在一些操作为单位时间操作的基础上。可是这些被认为的单位时间操作在我的实现中却有着平方复杂度,情何以堪,万恶的理论计算机科学家。

hopcroft实现的代码,太长了,还没写完。不过核心的子集分割已经完成了,剩下的就是分配节点及重新构建邻接表。明天再说吧。

  1 #include "dfa_to_dfa.h"
  2 pdfa_edge* rev_dfa_table;//作为dfa的反转表
  3 int* belong_to;//这个是用来标记每个节点所在的群的标号
  4 int** group_table;//这个是用来串联所有的群
  5 int group_index;//这个用来表明使用了多少号的群
  6 typedef struct _group_list
  7 //这个结构用来把所有的当前在使用的群的标号串联起来
  8 //这样就可以用来替代掉栈,而且也有利于遍历
  9 {
 10     struct _group_list* next;
 11     int group_number;
 12 }group_list,*pgroup_list;
 13 pgroup_list group_list_begin=NULL;//这个是链表的专用头节点
 14 void insert_group(int in_group_number)//将一个新的群号加入到群列表中,这里默认已经经过参数检查了
 15 {
 16     pgroup_list temp_list;
 17     temp_list=malloc(sizeof(struct _group_list));
 18     temp_list->group_number=in_group_number;
 19     temp_list->next=group_list_begin->next;
 20     group_list_begin->next=temp_list;
 21 }
 22 
 23 
 24 void reverse_dfa(void)//构建反转表
 25 {
 26     int for_travel;//遍历变量
 27     pdfa_edge temp_add;//作为反转表的增加边的变量
 28     pdfa_edge temp_travel;//用来遍历原来的dfa表的邻接表的变量
 29     int temp_dest;//增加边用的临时起始编号
 30     rev_dfa_table=malloc(sizeof(struct _dfa_edge)*(dfa_node_number+1));//分配表的内存,注意加1
 31     for(for_travel=1;for_travel<=dfa_node_number;for_travel++)
 32     {
 33         rev_dfa_table[for_travel]=NULL;//初始化为空
 34     }
 35     for(for_travel=1;for_travel<=dfa_node_number;for_travel++)
 36     {
 37         temp_travel=current_dfa_table[for_travel].begin;
 38         while(temp_travel!=NULL)
 39         {
 40             temp_add=malloc(sizeof(struct _dfa_edge));
 41             temp_add->destination_number=for_travel;
 42             temp_add->label=temp_travel->label;
 43             temp_dest=temp_travel->destination_number;
 44             temp_add->next=rev_dfa_table[temp_dest];
 45             rev_dfa_table[temp_dest]=temp_add;
 46         }
 47     }//现在已经完全构建好了反转表
 48 }
 49 
 50 
 51 
 52 typedef struct _rev_hash
 53 {
 54     int in_use;//0表示未使用,1表示正在使用,2表示已经删除
 55     char* name;
 56     int dfa_group_index;
 57 }rev_hash;
 58 rev_hash rev_hash_table[400];
 59 int insert_rev_hash(char* input_name,int dfa_group_pointer)//插入hash表
 60 {
 61     int for_i;
 62     unsigned int result;
 63     int counter;
 64     int byte_of_table;
 65     char* hash_name;
 66     byte_of_table=(dfa_node_number+7)/8;
 67     result=0;
 68     for(for_i=0;for_i<byte_of_table;for_i++)
 69     {
 70         result+=(unsigned int) input_name[for_i];
 71     }
 72     result=result%397;
 73     counter=0;
 74     while(counter<397)
 75     {
 76         if(rev_hash_table[result].in_use!=1)
 77         {
 78             rev_hash_table[result].dfa_group_index=dfa_group_pointer;
 79             rev_hash_table[result].in_use=1;
 80             hash_name=malloc(sizeof(char)*(byte_of_table+1));
 81             for(for_i=0;for_i<byte_of_table;for_i++)
 82             {
 83                 hash_name[for_i]=input_name[for_i];
 84             }
 85             hash_name[for_i]='';
 86             rev_hash_table[result].name=hash_name;
 87             return result;
 88         }
 89         result=(result+1)%397;
 90         counter++;
 91     }
 92     return -1;
 93 }
 94 int search_rev_hash(char* input_name)//根据名字来搜索hash表,如果存在则返回群标号
 95 {
 96     int for_i;
 97     unsigned int result;
 98     int counter;
 99     int byte_of_table;
100     char* hash_name;
101     int compare_result;
102     byte_of_table=(dfa_node_number+7)/8;
103     result=0;
104     for(for_i=0;for_i<byte_of_table;for_i++)
105     {
106         result+=(unsigned int) input_name[for_i];
107     }
108     result=result%397;
109     counter=0;
110     while(counter<397)
111     {
112         if(rev_hash_table[result].in_use==1)
113         {
114             compare_result=0;
115             for(for_i=0;for_i<byte_of_bitmap;for_i++)
116             {
117                 compare_result+=!((rev_hash_table[result].name)[for_i]==input_name[for_i]);
118             }
119             if(compare_result==0)
120             {
121                 return rev_hash_table[result].dfa_group_index;
122             }
123             else
124             {
125                 result=(result+1)%397;
126                 counter++;
127             }
128         }
129         else
130         {
131             if(rev_hash_table[result].in_use==2)
132             {
133                 result=(result+1)%397;
134                 counter++;
135             }
136             else
137             {
138                 return -1;
139             }
140         }
141     }
142     return -1;
143 }
144 
145 
146 void map_name(char* output,int group_number)//将一个群转换为字符串
147 {
148     int for_i,for_j;
149     for(for_i=0;for_i<=(dfa_node_number+7)/8;for_i++)
150     {
151         output[for_i]='';
152     }
153     for(for_i=0;for_i<dfa_node_number;for_i++)
154     {
155         if(*(*(group_table+group_number)+for_i)==1)
156         {
157             output[(for_i+7)/8]=BYTE_MASK>>(for_i%8)|output[(for_i+7)/8];
158         }
159     }
160 }
161 void delete_rev_hash(char* input_name)//从hash表中删除一个节点
162 {
163     int for_i;
164     unsigned int result;
165     int counter;
166     int byte_of_table;
167     char* hash_name;
168     int compare_result;
169     byte_of_table=(dfa_node_number+7)/8;
170     result=0;
171     for(for_i=0;for_i<byte_of_table;for_i++)
172     {
173         result+=(unsigned int) input_name[for_i];
174     }
175     result=result%397;
176     counter=0;
177     while(counter<397)
178     {
179         if(rev_hash_table[result].in_use==1)
180         {
181             compare_result=0;
182             for(for_i=0;for_i<byte_of_bitmap;for_i++)
183             {
184                 compare_result+=!((rev_hash_table[result].name)[for_i]==input_name[for_i]);
185             }
186             if(compare_result==0)
187             {
188                 rev_hash_table[result].in_use=2;
189             }
190             else
191             {
192                 result=(result+1)%397;
193                 counter++;
194             }
195         }
196         else
197         {
198             if(rev_hash_table[result].in_use==2)
199             {
200                 result=(result+1)%397;
201                 counter++;
202             }
203         }
204     }
205 }
206 
207 char* group_transition(int group_number,char input_label)//处理一个群在一个字母上的转移,结果以一个字符串来表示
208 {
209     char* result_return;
210     int for_i,for_j,for_k;
211     int temp_destination;
212     pdfa_edge temp_edge;
213     result_return=malloc(sizeof(char)*((dfa_node_number+7)/8+1));
214     for(for_i=0;for_i<=(dfa_node_number+7)/8;for_i++)
215     {
216         result_return[for_i]='';
217     }
218     for(for_i=0;for_i<dfa_node_number;for_i++)
219     {
220         if(*(*(group_table+group_number)+for_i)==1)
221         {
222             temp_edge=current_dfa_table[for_i+1].begin;
223             while((temp!=NULL)&&(temp->label!=input_label))
224             {
225                 temp=temp->next;
226             }
227             if(temp!=NULL)
228             {
229                 temp_destination=temp->destination_number;
230                 temp_destination--;//注意这里要减1
231                 result_return[(temp_destination+7)/8]=result_return[(temp_destination+7)/8]|BYTE_MASK>>(temp_destination%8);
232             }
233         }
234     }
235     return result_return;
236 }
237 
238 void intersect_group(int dest_group,int origin_group,char in_label)
239 {
240     int for_i,for_j,for_k;
241     char* dest;//最后用来注册hash表的名字
242     int* dest_number;//用来表示哪些是目标地址
243     pdfa_edge temp_edge;//用来遍历邻接表
244     int temp_dest_number;
245     dest=malloc(sizeof(char)*((dfa_node_number+7)/8+1));
246     dest_number=malloc(sizeof(int)*dfa_node_number);
247     *(group_table+group_index)=dest_number;//复制目标地址
248     for(for_i=0;for_i<dfa_node_number;for_i++)
249     {
250         dest_number[for_i]=0;
251     }//初始化
252     for(for_i=0;for_i<=(dfa_node_number+7)/8;for_i++)
253     {
254         dest[for_i]='';
255     }//初始化为0
256     group_index++;//建立一个新的群
257     for(for_i=0;for_i<dfa_node_number;for_i++)
258     {
259         if(*(*(group_table+origin_group)+for_i)==1)
260         {
261             temp_edge=rev_dfa_table[for_i=1];//注意加1
262             while(temp_edge!=NULL)
263             {
264                 if(temp_edge->label==in_label)
265                 {
266                     temp_dest_number=temp_edge->destination_number;
267                     temp_dest_number--;
268                     dest_number[temp_dest_number]=1;
269                 }
270                 temp_edge=temp_edge->next;
271             }
272         }
273     }//遍历邻接表完成
274     //然后取交集
275     for(for_i=0;for_i<dfa_node_number;for_i++)
276     {
277         if(*(*(group_table+dest)+for_i)==0)
278         {
279             dest_number[temp_dest_number]=0;
280         }
281     }//交集处理完成
282     for(for_i=0;for_i<dfa_node_number;for_i++)
283     {
284         if(dest_number[for_i]==1)
285         {
286             dest[for_i/8]=dest[for_i/8]|(BYTE_MASK>>for_i%8);
287             belong_to[for_i]=group_index;
288         }
289     }//名字及相应的群建立完成
290     insert_rev_hash(dest,group_index);//插入hash表中
291     free(dest);//释放内存空间
292 }
293 
294 
295 
296 
297 
298 
299 
300 void group_min_dfa(void)
301 {
302     char* temp_name;
303     int for_i,for_j;
304     pgroup_list before,current;//用来遍历整个群链表
305     int is_group_changed;//用来标志当前是否生成了新的群号,如果没有生成,则可以结束集合分割了
306     int* is_already_tackled=malloc(sizeof(int)*dfa_node_size;//这个是用来标志在处理分割集的时候哪些点已经用过了
307     belongto=malloc(sizeof(int)*dfa_node_number);
308     group_table=malloc(sizeof(int)*100);//这里可能有点小,但是就这么着吧,不够用了自己改
309     group_index++;
310     *(group_table+group_index)=malloc(sizeof(int)*dfa_node_number);//这个是用来标识属于接受节点的那些点
311     for(for_i=1;for_i<=dfa_node_number;for_i++)//初始化那些属于开始节点的群
312     {
313         if(current_dfa_table[for_i].is_end==1)
314         {
315             *(*(group_table+group_index)+for_i-1)=1;//注意这里要减一
316             *(belong_to+for_i-1)=group_index;
317         }
318         else
319         {
320             *(*(group_table+group_index)+for_i-1)=0;
321         }
322     }
323     temp_name=malloc(sizeof(char)*((dfa_node_number+7)/8+1));
324     map_name(temp_name,group_index);
325     insert_rev_hash(temp_name,group_index);
326     insert_group(group_index);
327     group_index++;
328     *(group_table+group_index)=malloc(sizeof(int)*dfa_node_number);//这个是用来标识属于非接受节点的那些点
329     for(for_i=1;for_i<=dfa_node_number;for_i++)//初始化那些不是接受节点所在的群
330     {
331         if(current_dfa_table[for_i].is_end==0)
332         {
333             *(*(group_table+group_index)+for_i-1)=1;//注意这里要减一
334             *(belong_to+for_i-1)=group_index;
335         }
336         else
337         {
338             *(*(group_table+group_index)+for_i-1)=0;
339         }
340     }
341     temp_name=malloc(sizeof(char)*((dfa_node_number+7)/8+1));
342     map_name(temp_name,group_index);
343     insert_rev_hash(temp_name,group_index);
344     insert_group_index;
345     //初始化工作完成
346     is_group_changed=1;
347     while(is_group_changed!=0)//现在开始遍历工作
348     {
349         is_group_changed=0;
350         before=group_list_begin;
351         current=before->next;
352         while(current!=NULL)//现在开始遍历整个群链表
353         {
354             int label_traverse;
355             char* name_for_transition;
356             for(label_traverse=0;label_traverse<alpha_size;label_traverse++)
357             {
358                 name_for_transition=group_transition(current->group_number,mini_alpha_set[label_traverse]);
359                 //这里进行边的转换,并为目标集合生成一个名字
360                 int search_hash_result=search_rev_hash(name_for_transition);//搜索这个名字是不是已经在群里面了
361                 if(search_hash_result==-1)//如果这个名字当前不存在,则需要分割
362                 {
363                     is_group_changed=1;//标志为已经改变
364                     //记录这个name里面包含的群,然后每个群再通过反向调整,并与当前群相交来建立新的群
365                     for(int for_k=0;for_k<dfa_node_number;for_k++)
366                     {
367                         is_already_tackled[for_k]=0;//初始化为未使用
368                     }
369                     for(int for_k=0;for_k<dfa_node_number;for_k++)//处理每一位
370                     {
371                         if(is_already_tackled[for_k]==0)
372                         {
373                             is_already_tackled[for_k]=1;
374                             if(name_for_transition[(for_k+7)/8]&(BYTE_MASK>>(for_k%8)))//如果这里被置位了
375                             {
376                                 int temp_group_number=belong_to[for_k];
377                                 for(int for_m=for_k;for_m<dfa_node_number;for_m++)
378                                 {
379                                     if(belong_to[for_m]==temp_group_number)
380                                     {
381                                         is_already_tackled[for_m]=1;
382                                     }
383                                 }//把属于一个群的全都标记为已经处理
384                                 //然后在对这个群与当前群来处理
385                                 intersect_group(current->group_number,temp_group_number,mini_alpha_set[label_traverse]);
386                                 //前面的函数来处理交集,并生成一个新的群,自动增加到hash中
387                                 if(before==group_list_begin)//插入群的时候需要考虑这个情况
388                                 {
389                                     pgroup_list temp_group_add=malloc(sizeof(struct _group_list));
390                                     temp_group_add->group_number=group_index;
391                                     temp_group_add->next=group_list_begin->next;
392                                     group_list_begin=temp_group_add;
393                                     before=temp_group_add;
394                                 }
395                                 else
396                                 {
397                                     pgroup_list temp_group_add=malloc(sizeof(struct _group_list));
398                                     temp_group_add->group_number=group_index;
399                                     temp_group_add->next=group_list_begin->next;
400                                     group_list_begin=temp_group_add;
401                                 }
402 
403                             }//相交群处理完成
404                         }//这个位处理完成
405                     }//所有位处理完成
406                     delete_hash(current->group_number);//从hash表中取消这个群名字的注册
407                     free(*(group_table+current->group_number);//释放这个名字所占的全局表空间
408                     *(group_table+current->group_number)=NULL;//一定要列为空
409                     current=current->next;//处理下一个群
410                     free(before->next);//释放空间
411                     before->next=current;//这样就把当前处理的群从当前链表中删去了
412                     break;//下面的字符就不需要处理了,直接跳出循环,处理下一个群标号
413                 }//当前群分割完成
414                 free(name_for_transition);//释放临时申请的内存
415             }//当前群处理完成
416         }//当前遍历完成
417     }//没有额外的群加入,所有的处理完成
418 
419     //现在所有的群都建造完成了
420     //现在的任务是重新建立dfa表
421     //这里需要确定哪些是开始节点,那些是结束节点,并做好标注
422     //具体代码就不详细写了,太尼玛累了
423 }
原文地址:https://www.cnblogs.com/huangfeidian/p/3161738.html