采取的方法是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(" "); 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 ",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 ",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 "); 262 }