dfa最小化,终于完成了。

采取的方法是hopcroft的填表法,详情见如下代码

  1 #include "nfa_to_dfa.h"
  2 int* dfa_diff_matrix;
  3 
  4 int mini_dfa_number;//这个是最小化的 dfa表的索引
  5 typedef struct _min_dfa_node
  6 {
  7     pdfa_edge begin;
  8     int is_end;//记录是否是接受节点
  9 }min_dfa_node,*pmin_dfa_node;
 10 min_dfa_node mini_dfa_table[100];//设定为100,其实也可以malloc一下,因为我们已经知道了有多少个节点了
 11 //为了偷懒,算了
 12 is_diff(int input_a,int input_b)//判断两个点是不是等价的程序,注意我们传参数的时候默认a比b大
 13 {
 14     int destination_a,destination_b;//临时的转换目标地址
 15     pdfa_edge temp_edge;//遍历邻接表 
 16     char label_traverse;//用来遍历符号表
 17     int for_i;
 18     for(for_i=0;for_i<alpha_size;for_i++)
 19     {
 20         label_traverse=mini_alpha_set[for_i];
 21         temp_edge=current_dfa_table[input_a].begin;
 22         while(temp_edge!=NULL&&temp_edge->label!=label_traverse)
 23         {
 24             temp_edge=temp_edge->next;
 25         }
 26         if(temp_edge==NULL)
 27         {
 28             destination_a=0;
 29         }
 30         else
 31         {
 32             destination_a=temp_edge->dest_dfa_index;
 33         }
 34         temp_edge=current_dfa_table[input_b].begin;
 35         while(temp_edge!=NULL&&temp_edge->label!=label_traverse)
 36         {
 37             temp_edge=temp_edge->next;
 38         }
 39         if(temp_edge==NULL)
 40         {
 41             destination_b=0;
 42         }
 43         else
 44         {
 45             destination_b=temp_edge->dest_dfa_index;
 46         }
 47         if(destination_a==destination_b)
 48         {
 49             //下一次吧
 50         }
 51         else
 52         {
 53             if(destination_a*destination_b==0)
 54             {
 55                 return 1;
 56             }
 57             else
 58             {
 59                 if( destination_a>destination_b)
 60                 {
 61                     if(dfa_diff_matrix[dfa_node_number*(input_a)+(input_b)]!=1)//如果当前无法判别
 62                     {
 63                         if(is_diff(destination_a,destination_b))//如果可以判别 
 64                         {
 65                             dfa_diff_matrix[dfa_node_number*(input_a)+(input_b)]=1;
 66                             return 1;
 67                         }
 68                         else
 69                         {
 70                             //继续判别 
 71                         }
 72                     }
 73                     else
 74                     {
 75                         return 1;
 76                     }
 77                 }
 78                 else
 79                 {
 80                     if(dfa_diff_matrix[dfa_node_number*(input_b)+(input_a)]!=1)//如果当前无法判别
 81                     {
 82                         if(is_diff(destination_b,destination_a))//如果可以判别 
 83                         {
 84                             dfa_diff_matrix[dfa_node_number*(input_b)+(input_a)]=1;
 85                             return 1;
 86                         }
 87                         else
 88                         {
 89                             //继续判别 
 90                         }
 91                     }
 92                     else
 93                     {
 94                         return 1;
 95                     }
 96                 }
 97             }
 98         }
 99     }
100     return 0;
101 }
102 void diff_matrix(void)
103 {
104     int already_diff_number;//这个是用来判断有多少个点已经经过了等价性测试
105     int for_i,for_j;
106     dfa_diff_matrix=malloc(sizeof(int)*dfa_node_number*dfa_node_number);//分配这个节点
107     for(for_i=0;for_i<dfa_node_number;for_i++)
108     {
109         for(for_j=0;for_j<dfa_node_number;for_j++)
110         {
111             dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=0;
112         }
113     }
114     for(for_i=1;for_i<dfa_node_number;for_i++)
115     {
116         for(for_j=0;for_j<for_i;for_j++)//这里首先根据是否是接受节点来初始化矩阵
117         {
118             if(current_dfa_table[for_i+1].is_end!=current_dfa_table[for_j+1].is_end)
119             {
120                 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1;
121             }
122         }
123     }
124     do{
125         already_diff_number=0;
126         for(for_i=1;for_i<dfa_node_number;for_i++)
127         {
128             for(for_j=0;for_j<for_i;for_j++)
129             {
130                 if(dfa_diff_matrix[(for_i)*dfa_node_number+for_j]!=1)
131                 {
132                     if(is_diff(for_i,for_j)==1)
133                     {
134                         dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1;
135                     }
136                 }
137             }
138         }
139     }while(already_diff_number!=0);//如果本趟处理没有找到新的可分节点,就结束 
140     for(for_i=0;for_i<dfa_node_number;for_i++)
141     {
142         for(for_j=0;for_j<dfa_node_number;for_j++)
143         {
144             printf("%d ",dfa_diff_matrix[(for_i)*dfa_node_number+for_j]);
145         }
146         printf("\n");
147     }
148 }
149 void minimize_dfa_matrix(void)//在已经构建好了dfa_diff_matrix后,开始群聚,并建图
150 {
151     //现在开始群聚 
152  int* already_in_group;//用来记录哪些点已经在群里面了
153  int* temp_group;
154  int* before_min_access;//这里来标注哪些节点已经通过了最简化dfa的转换 
155  int group_number=0;//注意群号由0开始 
156  int* index_of_group;
157  pdfa_edge temp_edge;//这个是用来重新建立最小化dfa的临时边
158  pdfa_edge temp_add_edge;//这个是用来往最小dfa里面增加边的临时边
159  int dest_group_number;//这个是在增加边的时候的目标编号
160  int **group_set;
161  int for_i,for_j;
162  group_set=malloc(sizeof(int)*dfa_node_number);
163  already_in_group=malloc(sizeof(int)*dfa_node_number);
164  for(for_i=0;for_i<dfa_node_number;for_i++)
165  {
166      already_in_group[for_i]=0;
167      *(group_set+for_i)=NULL;
168  }
169  for(for_i=0;for_i<dfa_node_number-1;for_i++)//聚集 
170  {
171      if(already_in_group[for_i]==0)
172      {
173          already_in_group[for_i]=1;
174          temp_group=malloc(sizeof(int)*dfa_node_number);
175          *(group_set+group_number++)=temp_group;
176          for(for_j=0;for_j<dfa_node_number;for_j++)
177          {
178              temp_group[for_j]=0;
179          }//注意这里也需要考虑加减1的问题
180          temp_group[for_i]=1;
181          for(for_j=for_i+1;for_j<dfa_node_number;for_j++)
182          {
183              if(!dfa_diff_matrix[(for_j)*dfa_node_number+for_i])
184              {
185                  temp_group[for_j]=1;
186                  already_in_group[for_j]=1;
187              }
188          }
189      }
190  }//现在已经完全都聚集为一团了
191  mini_dfa_number=group_number;
192  //现在再将节点和群的关系反转
193  index_of_group=malloc(sizeof(int)*dfa_node_number);
194  //这里又需要注意加减1的关系,由于这里dfa节点是从1标号的,而我们在index_of_group是从0标号的,要注意
195  for(for_i=0;for_i<dfa_node_number;for_i++)
196  {
197      index_of_group[for_i]=0;
198  }
199  for_i=0;
200  while(*(group_set+for_i)!=NULL)//前面开了一个索引数组,现在来赋值,这样就可以直接得到某个节点所在的群号
201  {
202      for(for_j=0;for_j<dfa_node_number;for_j++)
203      {
204          if(*(*(group_set+for_i)+for_j)==1)
205          {
206              index_of_group[for_j]=for_i;
207          }
208      }
209      for_i++;
210  }//现在关系已经翻转了
211  //下一步就是利用这个点与群的关系来新建立一个dfa图
212  //这里的群号就是节点的编号,由于每个群里面的节点都是等价的,所以只需要找一个节点就行了
213  for(for_i=1;for_i<=group_number;for_i++)//这里的for_i是用来表示最小dfa图的标号,所以从1开始
214  {
215      //对每一个群进行遍历
216      mini_dfa_table[for_i].begin=NULL;
217      mini_dfa_table[for_i].is_end=0;
218      for_j=0;
219      while(*(*(group_set+for_i-1)+for_j)!=1)//由于group是从0开始标号的,所以要减去1
220      {
221          for_j++;
222      }//找到这个群里面一个节点,注意加减一问题,少犯错误啊,1号节点存储在0号位置上
223      if(current_dfa_table[for_j+1].is_end)
224      {
225          mini_dfa_table[for_i].is_end=1;//标记为结束节点
226      }
227      temp_edge=current_dfa_table[for_j+1].begin;
228      while(temp_edge!=NULL)//重新建设邻接表
229      {
230          temp_add_edge=malloc(sizeof(struct _dfa_edge));
231          temp_add_edge->label=temp_edge->label;
232          temp_add_edge->next=mini_dfa_table[for_i].begin;
233          dest_group_number=index_of_group[temp_edge->dest_dfa_index-1]+1;//特别要注意这里的加一和减一
234          //由于temp_edge->dest_dfa_node是从1开始标号的,而index_of_group是从0开始标号的,所以我们要减一
235          //同样,又由于最后的最简化dfa的图是从1开始标号的,所以我们要加1;
236          temp_add_edge->dest_dfa_index=dest_group_number;
237          mini_dfa_table[for_i].begin=temp_add_edge;
238          temp_edge=temp_edge->next;
239      }
240      //本群的邻接表构建完成
241  }//所有群的邻接表构建完成
242 }
243 void show_mini_dfa(void)//输出图
244 {
245     int for_i;
246     pdfa_edge temp_dfa_edge;
247     number_of_end_dfa=0;
248     for(for_i=1;for_i<=mini_dfa_number;for_i++)
249     {
250         if(mini_dfa_table[for_i].is_end==1)
251         {
252             printf("this node is an destination node ,index is %d\n",for_i);
253         }
254         temp_dfa_edge=mini_dfa_table[for_i].begin;
255         while(temp_dfa_edge!=NULL)
256         {
257             printf("there is an dfa edge from %d to %d with label %c\n",for_i,temp_dfa_edge->dest_dfa_index,temp_dfa_edge->label);
258             temp_dfa_edge=temp_dfa_edge->next;
259         }
260     }
261     printf("the minimized dfa is completed\n");
262 }

 

posted @ 2013-06-27 15:13  huangnima  阅读(2502)  评论(0编辑  收藏  举报