zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    提高软件开发内功的推荐阅读列表
    oracle如何使用dblink链接另一个数据库
    代码不可读
    oracle如何使用dblink链接另一个数据库
    程序猿的吐槽三——改进还是不改进
    程序猿的吐槽一
    软件模式
    用户分类
    Matplotlib简介和pyplot的简单使用——subplot
    Linux下Eclipse的PyDev和CDT的安装和配置
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3161738.html
Copyright © 2011-2022 走看看