2021-04-11|2021-04-11 子集构造法有效性证明
本文主要介绍一下编译原理中的子集构造法的数学依据。
龙书中并没有给出证明,我们在这里补上。
网上虽然有一些证明,但大多数不是很细,这里给出一个详细的证明
NFA的形式化定义如下:
为一个5元组
其中是所有状态的集合,是符号集合,
是一个映射: (其中表示的所有子集的集合,对于该映射的像为空集的情形,把对应原像从定义域中排除,从而使得该映射的定义域为的子集,这一点后文中保持一致并且不再说明)
为初始状态集合
是终止状态集合
DFA为NFA的特例,满足以下两个额外条件:
1,只包含一个元素
2, 的任意象 都最多只包含一个元素
以上形式化定义十分抽象,但其实NFA只不过表达了一个无重边的有向图,对应图的节点,对应图的边上的符号,若 则表示,到中每个元素都有一条有向边,且这些边上的符号为, 和仅仅是的特殊子集
子集构造法主要是把一个转化为一个,为了给出其形式化描述,我们先给出以下定义:
1,给定
给定任意子集,以及任意一个符号
令
待构建的DFA记为:
则有 ,,
注意,根据的定义,其象最多只能包含一个元素,对于只包含一个元素的集合,我们这个元素替代,而对于不包含任何元素的集合,我们可以把其原像从定义域中排除;则上式可以简写为:
但是这个映射的定义域并非而是其 子集。
简单来说,的状态是 原始的状态集合,其映射把某个状态 和 某个符号映射为唯一的状态,但是有些映射的像为空(这些映射的原像将被我们从定义域 中排除)
有了以上铺垫,我们用伪代码的形式,形式化的描述子集构造法:
0,初始5元组中所有集合为空集,的定义域为空集
1取定并将其添加到 ,并令为未标定态
2,
K's
标定
(若(s,c)不在定义域,则continue)
(箭头这里表示添加的意思,同时令该t为未标定态)
在的定义域中添加,并令
以上算法确定了除了之外的所有元素,之后我们把中所有包含位于中元素的的对象取出组成一个集合,设为
至此我们按照算法完全构建了
下面我们来做最关键的一步,证明以下两点:
1,子集构造法生成的图 确实满足应该满足的性质
2, 该DFA和原始NFA表达相同的语言
证明:
1, 应该满足的性质为:
1-1,只包含一个元素
1-2, 的任意象 都最多只包含一个元素
根据我们的构建算法,中只包含,因此1成立,且由于是单值映射,显然2成立
2,该DFA和原始NFA表达相同的语言
2-1
首先证明原始NFA的语言包含于DFA
我们把形如:
的关系简称为“包含链”,当时,
对于NFA表达的语言中的任意一条语句,,显然必然存在满足上述条件的包含链
对于这样一条语句,我们考虑DFA构造方法,
有
会被执行一次标定,之后对于符号,将执行
以及
由 ,, 推出
并且将有:我们设;
则会被执行一次标定,之后对于符号将执行
任意 以及
由,推出
并且将有: 令;
.......,最终得到:
而这等价于是说:属于 该DFA的语言。
从最初选择的语句的任意性,证明完毕
2-2 其次证明DFA的语言不会超过NFA的语言,
DFA表达的语言中任意语句:根据DFA映射特性,存在唯一的满足以下条件:
1)
我们考虑其中任意一个片段:
根据构造算法,
将被执行一次,之后不会再被修改
这意味着中任意元素都,存在中至少一个元素使得
【2021-04-11|2021-04-11 子集构造法有效性证明】利用这个关系,我们不难推导出,存在元素:
满足
结合
这对应着NFA中的一条语句
证明完毕
推荐阅读
- Nginx|Nginx Tomcat 构造https服务应对苹果要求
- JavaScript|JavaScript - 子集1(回溯法)
- Java构造器与传值学习总结
- 第12章|第12章 面向对象第四讲
- Scala|Scala 从Array数组的构造过程理解apply()
- leetcode题解|leetcode#106. 从中序与后序遍历序列构造二叉树
- 416.|416. 分割等和子集
- js的构造函数
- 416.分割等和子集
- Spring-依赖注入