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

时间:2022-12-26 15:02:09

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

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

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

 #include "dfa_to_dfa.h"
pdfa_edge* rev_dfa_table;//作为dfa的反转表
int* belong_to;//这个是用来标记每个节点所在的群的标号
int** group_table;//这个是用来串联所有的群
int group_index;//这个用来表明使用了多少号的群
typedef struct _group_list
//这个结构用来把所有的当前在使用的群的标号串联起来
//这样就可以用来替代掉栈,而且也有利于遍历
{
struct _group_list* next;
int group_number;
}group_list,*pgroup_list;
pgroup_list group_list_begin=NULL;//这个是链表的专用头节点
void insert_group(int in_group_number)//将一个新的群号加入到群列表中,这里默认已经经过参数检查了
{
pgroup_list temp_list;
temp_list=malloc(sizeof(struct _group_list));
temp_list->group_number=in_group_number;
temp_list->next=group_list_begin->next;
group_list_begin->next=temp_list;
} void reverse_dfa(void)//构建反转表
{
int for_travel;//遍历变量
pdfa_edge temp_add;//作为反转表的增加边的变量
pdfa_edge temp_travel;//用来遍历原来的dfa表的邻接表的变量
int temp_dest;//增加边用的临时起始编号
rev_dfa_table=malloc(sizeof(struct _dfa_edge)*(dfa_node_number+));//分配表的内存,注意加1
for(for_travel=;for_travel<=dfa_node_number;for_travel++)
{
rev_dfa_table[for_travel]=NULL;//初始化为空
}
for(for_travel=;for_travel<=dfa_node_number;for_travel++)
{
temp_travel=current_dfa_table[for_travel].begin;
while(temp_travel!=NULL)
{
temp_add=malloc(sizeof(struct _dfa_edge));
temp_add->destination_number=for_travel;
temp_add->label=temp_travel->label;
temp_dest=temp_travel->destination_number;
temp_add->next=rev_dfa_table[temp_dest];
rev_dfa_table[temp_dest]=temp_add;
}
}//现在已经完全构建好了反转表
} typedef struct _rev_hash
{
int in_use;//0表示未使用,1表示正在使用,2表示已经删除
char* name;
int dfa_group_index;
}rev_hash;
rev_hash rev_hash_table[];
int insert_rev_hash(char* input_name,int dfa_group_pointer)//插入hash表
{
int for_i;
unsigned int result;
int counter;
int byte_of_table;
char* hash_name;
byte_of_table=(dfa_node_number+)/;
result=;
for(for_i=;for_i<byte_of_table;for_i++)
{
result+=(unsigned int) input_name[for_i];
}
result=result%;
counter=;
while(counter<)
{
if(rev_hash_table[result].in_use!=)
{
rev_hash_table[result].dfa_group_index=dfa_group_pointer;
rev_hash_table[result].in_use=;
hash_name=malloc(sizeof(char)*(byte_of_table+));
for(for_i=;for_i<byte_of_table;for_i++)
{
hash_name[for_i]=input_name[for_i];
}
hash_name[for_i]='\0';
rev_hash_table[result].name=hash_name;
return result;
}
result=(result+)%;
counter++;
}
return -;
}
int search_rev_hash(char* input_name)//根据名字来搜索hash表,如果存在则返回群标号
{
int for_i;
unsigned int result;
int counter;
int byte_of_table;
char* hash_name;
int compare_result;
byte_of_table=(dfa_node_number+)/;
result=;
for(for_i=;for_i<byte_of_table;for_i++)
{
result+=(unsigned int) input_name[for_i];
}
result=result%;
counter=;
while(counter<)
{
if(rev_hash_table[result].in_use==)
{
compare_result=;
for(for_i=;for_i<byte_of_bitmap;for_i++)
{
compare_result+=!((rev_hash_table[result].name)[for_i]==input_name[for_i]);
}
if(compare_result==)
{
return rev_hash_table[result].dfa_group_index;
}
else
{
result=(result+)%;
counter++;
}
}
else
{
if(rev_hash_table[result].in_use==)
{
result=(result+)%;
counter++;
}
else
{
return -;
}
}
}
return -;
} void map_name(char* output,int group_number)//将一个群转换为字符串
{
int for_i,for_j;
for(for_i=;for_i<=(dfa_node_number+)/;for_i++)
{
output[for_i]='\0';
}
for(for_i=;for_i<dfa_node_number;for_i++)
{
if(*(*(group_table+group_number)+for_i)==)
{
output[(for_i+)/]=BYTE_MASK>>(for_i%)|output[(for_i+)/];
}
}
}
void delete_rev_hash(char* input_name)//从hash表中删除一个节点
{
int for_i;
unsigned int result;
int counter;
int byte_of_table;
char* hash_name;
int compare_result;
byte_of_table=(dfa_node_number+)/;
result=;
for(for_i=;for_i<byte_of_table;for_i++)
{
result+=(unsigned int) input_name[for_i];
}
result=result%;
counter=;
while(counter<)
{
if(rev_hash_table[result].in_use==)
{
compare_result=;
for(for_i=;for_i<byte_of_bitmap;for_i++)
{
compare_result+=!((rev_hash_table[result].name)[for_i]==input_name[for_i]);
}
if(compare_result==)
{
rev_hash_table[result].in_use=;
}
else
{
result=(result+)%;
counter++;
}
}
else
{
if(rev_hash_table[result].in_use==)
{
result=(result+)%;
counter++;
}
}
}
} char* group_transition(int group_number,char input_label)//处理一个群在一个字母上的转移,结果以一个字符串来表示
{
char* result_return;
int for_i,for_j,for_k;
int temp_destination;
pdfa_edge temp_edge;
result_return=malloc(sizeof(char)*((dfa_node_number+)/+));
for(for_i=;for_i<=(dfa_node_number+)/;for_i++)
{
result_return[for_i]='\0';
}
for(for_i=;for_i<dfa_node_number;for_i++)
{
if(*(*(group_table+group_number)+for_i)==)
{
temp_edge=current_dfa_table[for_i+].begin;
while((temp!=NULL)&&(temp->label!=input_label))
{
temp=temp->next;
}
if(temp!=NULL)
{
temp_destination=temp->destination_number;
temp_destination--;//注意这里要减1
result_return[(temp_destination+)/]=result_return[(temp_destination+)/]|BYTE_MASK>>(temp_destination%);
}
}
}
return result_return;
} void intersect_group(int dest_group,int origin_group,char in_label)
{
int for_i,for_j,for_k;
char* dest;//最后用来注册hash表的名字
int* dest_number;//用来表示哪些是目标地址
pdfa_edge temp_edge;//用来遍历邻接表
int temp_dest_number;
dest=malloc(sizeof(char)*((dfa_node_number+)/+));
dest_number=malloc(sizeof(int)*dfa_node_number);
*(group_table+group_index)=dest_number;//复制目标地址
for(for_i=;for_i<dfa_node_number;for_i++)
{
dest_number[for_i]=;
}//初始化
for(for_i=;for_i<=(dfa_node_number+)/;for_i++)
{
dest[for_i]='\0';
}//初始化为0
group_index++;//建立一个新的群
for(for_i=;for_i<dfa_node_number;for_i++)
{
if(*(*(group_table+origin_group)+for_i)==)
{
temp_edge=rev_dfa_table[for_i=];//注意加1
while(temp_edge!=NULL)
{
if(temp_edge->label==in_label)
{
temp_dest_number=temp_edge->destination_number;
temp_dest_number--;
dest_number[temp_dest_number]=;
}
temp_edge=temp_edge->next;
}
}
}//遍历邻接表完成
//然后取交集
for(for_i=;for_i<dfa_node_number;for_i++)
{
if(*(*(group_table+dest)+for_i)==)
{
dest_number[temp_dest_number]=;
}
}//交集处理完成
for(for_i=;for_i<dfa_node_number;for_i++)
{
if(dest_number[for_i]==)
{
dest[for_i/]=dest[for_i/]|(BYTE_MASK>>for_i%);
belong_to[for_i]=group_index;
}
}//名字及相应的群建立完成
insert_rev_hash(dest,group_index);//插入hash表中
free(dest);//释放内存空间
} void group_min_dfa(void)
{
char* temp_name;
int for_i,for_j;
pgroup_list before,current;//用来遍历整个群链表
int is_group_changed;//用来标志当前是否生成了新的群号,如果没有生成,则可以结束集合分割了
int* is_already_tackled=malloc(sizeof(int)*dfa_node_size;//这个是用来标志在处理分割集的时候哪些点已经用过了
belongto=malloc(sizeof(int)*dfa_node_number);
group_table=malloc(sizeof(int)*);//这里可能有点小,但是就这么着吧,不够用了自己改
group_index++;
*(group_table+group_index)=malloc(sizeof(int)*dfa_node_number);//这个是用来标识属于接受节点的那些点
for(for_i=;for_i<=dfa_node_number;for_i++)//初始化那些属于开始节点的群
{
if(current_dfa_table[for_i].is_end==)
{
*(*(group_table+group_index)+for_i-)=;//注意这里要减一
*(belong_to+for_i-)=group_index;
}
else
{
*(*(group_table+group_index)+for_i-)=;
}
}
temp_name=malloc(sizeof(char)*((dfa_node_number+)/+));
map_name(temp_name,group_index);
insert_rev_hash(temp_name,group_index);
insert_group(group_index);
group_index++;
*(group_table+group_index)=malloc(sizeof(int)*dfa_node_number);//这个是用来标识属于非接受节点的那些点
for(for_i=;for_i<=dfa_node_number;for_i++)//初始化那些不是接受节点所在的群
{
if(current_dfa_table[for_i].is_end==)
{
*(*(group_table+group_index)+for_i-)=;//注意这里要减一
*(belong_to+for_i-)=group_index;
}
else
{
*(*(group_table+group_index)+for_i-)=;
}
}
temp_name=malloc(sizeof(char)*((dfa_node_number+)/+));
map_name(temp_name,group_index);
insert_rev_hash(temp_name,group_index);
insert_group_index;
//初始化工作完成
is_group_changed=;
while(is_group_changed!=)//现在开始遍历工作
{
is_group_changed=;
before=group_list_begin;
current=before->next;
while(current!=NULL)//现在开始遍历整个群链表
{
int label_traverse;
char* name_for_transition;
for(label_traverse=;label_traverse<alpha_size;label_traverse++)
{
name_for_transition=group_transition(current->group_number,mini_alpha_set[label_traverse]);
//这里进行边的转换,并为目标集合生成一个名字
int search_hash_result=search_rev_hash(name_for_transition);//搜索这个名字是不是已经在群里面了
if(search_hash_result==-)//如果这个名字当前不存在,则需要分割
{
is_group_changed=;//标志为已经改变
//记录这个name里面包含的群,然后每个群再通过反向调整,并与当前群相交来建立新的群
for(int for_k=;for_k<dfa_node_number;for_k++)
{
is_already_tackled[for_k]=;//初始化为未使用
}
for(int for_k=;for_k<dfa_node_number;for_k++)//处理每一位
{
if(is_already_tackled[for_k]==)
{
is_already_tackled[for_k]=;
if(name_for_transition[(for_k+)/]&(BYTE_MASK>>(for_k%)))//如果这里被置位了
{
int temp_group_number=belong_to[for_k];
for(int for_m=for_k;for_m<dfa_node_number;for_m++)
{
if(belong_to[for_m]==temp_group_number)
{
is_already_tackled[for_m]=;
}
}//把属于一个群的全都标记为已经处理
//然后在对这个群与当前群来处理
intersect_group(current->group_number,temp_group_number,mini_alpha_set[label_traverse]);
//前面的函数来处理交集,并生成一个新的群,自动增加到hash中
if(before==group_list_begin)//插入群的时候需要考虑这个情况
{
pgroup_list temp_group_add=malloc(sizeof(struct _group_list));
temp_group_add->group_number=group_index;
temp_group_add->next=group_list_begin->next;
group_list_begin=temp_group_add;
before=temp_group_add;
}
else
{
pgroup_list temp_group_add=malloc(sizeof(struct _group_list));
temp_group_add->group_number=group_index;
temp_group_add->next=group_list_begin->next;
group_list_begin=temp_group_add;
} }//相交群处理完成
}//这个位处理完成
}//所有位处理完成
delete_hash(current->group_number);//从hash表中取消这个群名字的注册
free(*(group_table+current->group_number);//释放这个名字所占的全局表空间
*(group_table+current->group_number)=NULL;//一定要列为空
current=current->next;//处理下一个群
free(before->next);//释放空间
before->next=current;//这样就把当前处理的群从当前链表中删去了
break;//下面的字符就不需要处理了,直接跳出循环,处理下一个群标号
}//当前群分割完成
free(name_for_transition);//释放临时申请的内存
}//当前群处理完成
}//当前遍历完成
}//没有额外的群加入,所有的处理完成 //现在所有的群都建造完成了
//现在的任务是重新建立dfa表
//这里需要确定哪些是开始节点,那些是结束节点,并做好标注
//具体代码就不详细写了,太尼玛累了
}

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

  1. dfa最小化,修正了上个版本的一些错误。

    上个版本测试的时候,只用了两个非常简单的测试用例,所以好多情况有问题却没有测试出来 bug1:在生成diff_matrix的时候,循环变量少循环了一次,导致最后一个节点在如果无法与其他点合并的情况下, ...

  2. 编译原理中DFA最小化

    关于编译原理最小化的操作,专业术语请移步至:http://www.360doc.com/content/18/0601/21/11962419_758841916.shtml 这里只是记录一下个人的理 ...

  3. DFA最小化,语法分析初步

    1.将DFA最小化:教材P65 第9题 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 语言:(01 | 10)*(01 | 10) 自动机图: DFA状态转换矩阵 ...

  4. 编译原理之DFA最小化,语法分析初步

    1.将DFA最小化: 状态转换图: 识别语言:b*ac*(da)*bb* 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 (1)正规式: S -> 0(1S+ ...

  5. 第九次作业 DFA最小化,语法分析初步

    1.将DFA最小化:教材P65 第9题 Ⅰ {1,2,3,4,5} {6,7} {1,2}b={1,2,3,4,5} 3,4}b={5} {6,7} Ⅱ {1,2}{3,4}{5} {6,7} 2.构 ...

  6. 编译原理:DFA最小化,语法分析初步

    1.将DFA最小化:教材P65 第9题   解析: 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 解析: S→ 0A|1B →S → 0(1S|1)|1(0S|0 ...

  7. DFA 最小化

    NDFA.εNDFA 确定化的细节这里就不总结了,这里说一说DFA最小化的算法. 关于DFA最小化,

  8. 第九次作业——DFA最小化,语法分析初步

    老师:MissDu 提交作业 1.将DFA最小化:教材P65 第9题 答: 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 3.自上而下语法分析,回溯产生的原因是 ...

  9. 作业九——DFA最小化

    1.将DFA最小化:教材P65 第9题 I {1, 2, 3, 4, 5} {6, 7} {1, 2}b->{1, 2, 3, 4, 5} {3, 4}b->{6, 7} {5}b-&gt ...

随机推荐

  1. 基于ionic&plus;angulajs的混合开发实现地铁APP

    基于ionic+angulajs的混合开发实现地铁APP 注:本博文为博主原创,转载时请注明出处. 项目源码地址:https://github.com/zhangxy1035/SubwayMap 一. ...

  2. Tomcat 内存和线程配置优化

    1. tomcat 的线程配置参数详情如下: 修改conf/server.xml中的<Connector .../> 节点如下: <Connector port="8080 ...

  3. Python常用网页字符串处理技巧

    首先一些Python字符串处理的简易常用的用法.其他的以后用到再补充. 1.去掉重复空格 s = "hello hello hello" s = ' '.join(s.split( ...

  4. 四款超棒的jQuery数字化签名插件

    在浏览器中,我们有很多方式来绘制生成签名效果,并且有很多很棒很智能的jQuery插件.数字化签名是未来的发展方向,正是这个原因我们这里收集并且推荐了四款超棒的jQuery数字化签名插件,希望大家喜欢! ...

  5. 无法从带有索引像素格式的图像创建graphics对象&lpar;转&rpar;

    大家在用 .NET 做图片水印功能的时候, 很可能会遇到 “无法从带有索引像素格式的图像创建graphics对象”这个错误,对应的英文错误提示是“A Graphics object cannot be ...

  6. SQL Server 查看正在运行的事务信息的 2 种方法。

    方法 1.sys.dm_tran_session_transactions; 方法 2.dbcc opentran ------------------------------------------ ...

  7. HTML 5 &lt&semi;details&gt&semi; 标签

    <details> 标签用于描述文档或文档某个部分的细节. <details> <summary>Copyright 2011.</summary> & ...

  8. asp&period;net MVC Session锁的问题

    一直在用Session,对Session锁并没有太多的关注,可能是平时没有注意.前段时间突然发现,一个Ajax Get请求,直接访问地址,只需要几十ms,但是在页面中加载,却需要2s.最后定位到Ses ...

  9. java基础-String不可变的好处

    一.java内部String类的实现: java 8: public final class String implements java.io.Serializable, Comparable&lt ...

  10. 秒杀linux下系统调用fork&lpar;&rpar;面试题(转)

    https://blog.csdn.net/chdhust/article/details/10579001 https://www.cnblogs.com/clover-toeic/p/375443 ...