形式语言与编译(二)NFA
正则语言
如果某个语言能被DFA识别,那么它就是正则的
例题1:
构造一个字母表为{0,1}的DFA,使其接受所有最多含有三个1的串。
例题2:
构造一个DFA,使其能够定义如下语言:
L={010,1} \(\Sigma=\{0,1\}\)
处理不了的话,可以引入一个特殊状态——死状态Qdie,这是严格要求的DFA
不严格的DFA则通常只写有意义可以到达的边,不可处理的边省略不写
对应到转移表(迁移表)的话,严格要求的话我们通常在表中不可到位置写qdie;不严格要求的话,我们通常就直接在表中用空项,表示不可处理
例题3:
字母表是\(\Sigma=\{0,1\}\),构造识别偶数个0和偶数个1的DFA.(DFA识别的一定是正则表达式,以后我就不说明了)
例题4:
\( L=\{w|w\in\{0,1\}^*\}\)且w 看做二进制数 能被5整除
例题5:
构造自动机DFA,让其能够识别正则串并且以01结尾的串
构造自动机DFA,让其能够识别正则串并且以101结尾的串
虽然DFA简单,但是表达能力不强,比如上述题,检测位数越多,状态图呈爆炸增长,\(2^5\),\(2^6\),\(2^7\),这么多状态几乎不可能编程序检测。因此提升DFA能力非常有必要。
NFA
非确定性的有限自动机
这个机器允许我们去猜[option] ,也就是遇到同样一件事有几条路径。
DFA可以看成函数,一一映射
NFA则可以看成多值"函数",一对多 NFA包含DFA
q3状态下,再继续读入0或者1,就"憋死了”
DFA里每一个输入都有明确的单一转移(1),NFA则就存在,转不成或者转的多(0,1,more)
面对NFA个多个路径,我们需要 遍历穷举
一般地,给出一个NFA,一个串,我们可以把所有的路径可以列出来,在列出来的所有路径中寻找happy path(我们需要的正确路径)。输入处理完,看是否是接受状态。
\(\delta_{NFA}\)是一个一对多的函数
\(\delta_{DFA}\)是一个一对一的函数
\(\delta(q_0,1)=q_0或q_1\) \(\delta(q_2,0)=空状态\) 这两个转移函数是NFA区别于DFA的最大不同
NFA遍历所有可能路径,有时候幸运,可能比较早找到happy path,有时候比较晚找到happy path;有时候则完全彻底遍历完,仍然找不到happy path,则拒绝这个串。
数学(形式)描述:
需要注意的是:
这个形式描述。(五元组中的其他4个形式描述与DFA差不太多)
因为\(\Sigma \cup \{\varepsilon\}\)的定义方式,这种NFA通常叫做带\(\varepsilon\)的NFA
正常的NFA,这里的定义应该是\(\Sigma\) 即可。
引入带\(\varepsilon\) 的NFA是为了更方便的构造,人为构造会更加方便。后面我会说
NFA和带\(\varepsilon\)的NFA 用程序实现起来不如DFA那么方便,后面会引入怎么把NFA转换成DFA。这在实验中是非常有必要实现的。
如何使用NFA来处理串?也就是遍历状态,当w被处理完了,看是否有当前状态是否是终止状态。简单。不讲了
NFA的扩展转移函数
实际核心就是将 串=子串+一个字符
与DFA的扩展转移函数实际并无多大差别。略
例题:
最终是\(\{q_0,q_2\}\)这个是接受状态(可能是有q2的原因,也就是其中有一个状态被接受就行)
最终的状态子集表达了所有的可能路径 。有一个状态accepted就可以啦
上面的严格数学定义: