形式语言与自动机这门课程不同于操作系统这种偏概念性的学科,需要结合习题才能真正掌握,所以下面总结的基本都是一些做题方法,可以在后期期末复习的时候使用;
至于初学者怎么上手学习推荐看书+视频课
语言L是句子的集合,当含有穷个句子时L为有穷语言,含无穷可数个句子时L为无穷语言;
E是一个字母表,L包含于E的【克林闭包】,则称L是E上的一个语言;

语言的特殊运算法则:


确定有穷状态自动机DFA

要求构造识别某个语言的DFA时,按照上述的步骤进行即可,非常简单;
需要注意一个定理

该定理只能用于DFA(不能直接用于NFA),可以帮助我们非常方便的构造某个语言的反例,只需要将原本DFA的终止状态和非终止状态互换即可(注意是否包含空串),如
这是识别语言{x不含空串且x含10110的子串}
这是识别语言{x不含空串且x不含10110的子串}
非确定有穷状态自动机NFA

当要求构造能够识别语言的NFA时,通常其做法比DFA简单的多(除了待会要说的例外),只需要分析需要几种状态并直接顺着弧线往下写就行,多写弧线并不会扣分;

注意:
带空移动的非确定有穷状态自动机s-NFA

注意:
书上的方法太容易混淆了,这里我们就使用此处介绍的方法即可;
一定要标记始末状态,DFA的初始状态为s-NFA初始状态的闭包,DFA的终止状态为包含s-NFA的终止状态的状态集合;
关于DFA的初始状态怎么求,一定要注意是s-NFA的初始状态的闭包;
某个状态qi的闭包的求法是包括自身,经过任意步数的空移动能够到达的【全部】状态的集合;
关于DFA的格子,并不是简单的读入字符移动到某个状态集合(如{q0,q1}),而是移动到的状态集合的s-闭包(如{q0,q1,q2,q3});

这里我们使用右线性文法举例,右线性文法的定义是,产生式集P中的产生式形如 A->w , A->wB;
考点是给出FA(一般是状态转移图形式),构造所给的DFA对应的右线性文法;
基本步骤:
(1)预处理,先去除不可达状态和陷阱状态;
(2)使用变量一一对应状态(当然这一步完全可以省略,便于直接读图写产生式),如S对应q0起始状态、A对应q1状态、B对应q2状态;
(3)文法的产生式与状态转移函数一一对应,通过读图知道状态转移函数进而写出文法产生式;
需要注意的是,每个变量的产生式只根据其出边的状态转移函数构造,且若下一个状态是终止状态,则可以产生终极符号|终极符号 终止状态;

这里常见的考题将左线性或右线性文法转换为FA都有,我们常使用状态转移图来表示得到的FA;
解题方法使用构图法:
(1)在原有变量的基础上需要额外增加一个终止状态变量Z;
(2)通过文法产生式与状态转移函数的一一对应,可以直接根据文法作图;
注意:

这里展示将右线性文法转换为FA

这里展示将左线性文法转换为FA


Moore机处理一个字符串时每经过一个状态,输出一个字符——输出的字符和状态一一对应;
Mealy机处理一个字符串时每一个移动输出一个字符——输出字符和移动一一对应;

FA与RE等价

下面这两种类型的题都需要参考哈工大的解法,如果参照书本或者之前的解法,考试的时候根本没办法画的出来;


从左到右,按照运算时的优先级画图构造;

有关泵引理需要补充几点:



关于上面的填表算法,需要补充:


若CFG G,则G的语言指的是从初始符号推导出的所有终结符的串的集合;

关于语法分析树,也称派生树,书上的介绍很少,但是作业题中出现了相关的考点:
(1)根据已知语法分析树给出其结果的最左派生(推导也称为派生):这种题做法就是直接顺着根节点往下,逐步利用产生式替换最左边出现的变量

该语法树对应的最左派生为

(2)第二种考点是写出派生树有多少种不同派生,关键在于排列组合

(3)第三种考点是根据派生树写出相应的CFG,做法就是直接读图写变量的产生式即可(树上有什么就写什么,空串也要写,但是派生树终极结果可以忽略空串)




删除空产生式是删除自己的空产生式,弥补别人;
删除单一产生式是删除自己的单一产生式,弥补自己;

注意:关于删除单一产生式,只有A->w这种才不算单一产生式,形如B->B或者A->B或者S->A这种都是单一产生式,必须全部删除(对于B->B这种直接在原产生式中删除即可)


注意:
这里尤其要注意一点,考题可能会给出一个未化简的式子,所以假如未化简我们需要使用上面的 删除无用符号-去除空产生式-去除单一产生式-删除无用符号 的步骤进行化简;
其次是注意,对【句型aAdB】中的终极符需要构建产生式替代,如果产生式右边是【句子abcd】也需要进行替换,将所有产生式处理为产生式右边【全是】变量符号ABCD或者【只有一个】终极符a;
最后是引入的符号最好可以区分,比如第一次处理引入的符号为C D,则第二次引入的符号应该是B1 B2


注意点:


本质上就是在Pf露出栈顶X0的时候(也就是Pn栈空了),直接转移到Pf的接收状态,因为对所有的Pn的状态都有可能被终态接受,所以为每一个状态添加转移;


本质上就是在Pf的接收状态时,给Pf的接收状态补充一个弹栈的操作,可以直接清栈,但是给每个接收状态都这样做比较麻烦,所以干脆直接将所有接收状态空转移到新的终态P再清栈;


尽管说是任何CFG可以转换为PDA,但注意我们还是应该对CFG进行化简后再使用;
当CFG是GNF的时候我们有一种更简单的转换方法(当然简单的CFG我们就没必要再花费时间转换为GNF再转换为PDA)

下面来看两道例题,区分CFG和GNF转换为PDA Pn的不同


下面给出一道例题便于理解


注意:









上一章介绍的图灵机与短语结构文法是等价的,这里不再给出证明;
本章主要介绍识别上下文有关语言CLS的工具——线性有界自动机LBA;
LBA是一种非确定的图灵机:

很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我有一个名为posts的模型,它有很多附件。附件模型使用回形针。我制作了一个用于创建附件的独立模型,效果很好,这是此处说明的View(https://github.com/thoughtbot/paperclip):@attachment,:html=>{:multipart=>true}do|form|%>posts中的嵌套表单如下所示:prohibitedthispostfrombeingsaved:@attachment,:html=>{:multipart=>true}do|at_form|%>附件记录已创建,但它是空的。文件未上传。同时,帖子已成功创建...有什么想法吗?
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?