软件设计师-2.程序设计语言

2.1 程序设计语言及其构成

2.1.1程序设计语言

计算机要通过程序或指令来控制才能完成各种任务。 程序设计语言(计算机语言):人与机器交换信息的语言。

阶段:

  1. 机器语言(低级语言):二进制指令代码,直观性差,容易出错,计算机直接执行
  2. 汇编语言(低级语言):用简单的符号代替部分指令,推广移植困难,需经汇编程序转化后执行
  3. 高级语言:更符号人的思维,易读易记,便于推广,有解释编译两种执行方式

2.1.2 高级程序设计语言划分

从客观系统描述划分:

  • 面向过程语言:
    • 命令式语言:FORTRAN、ALGOL、COBOL、C和Pascal等
    • 结构化语言(也属于命令式):C、Pascal 等
    • 函数式语言: Lisp 等
    • 逻辑式编程语言:Prolog 等
  • 面向对象语言:PHP、Delphi、Java、C++、Smalltalk、Python、C# 等

从程序执行角度划分:

  • 编译类程序设计语言:C、C++、Delphi、Java
  • 解释类程序设计语言:Python、PHP、Ruby、JavaScript
  • 脚本语言:通常为解释执行。JavaScript为客户端脚本语言,Python、Ruby、PHP 为服务器端脚本语言

2.1.3 常见的高级程序设计语言

  • Fortran语言:第一个高级程序设计语言,用于并行计算、科学计算和高性能计算。
  • Lisp语言:函数式程序语言,符号处理,人工智能
  • Prolog :逻辑式语言,建造专家系统、自然语言理解、智能知识库等
  • SQL:结构化查询语言,特殊目的的编程语言,用于查询、更新和管理关系数据库

通用的程序设计语言:C、C#、C++、Java、PHP、Python、JavaScript 等。

  • C语言:通用、结构化程序设计语言,简洁丰富可移植,能访问操作系统和底层硬件
  • C#语言:面向对象,运行于 .NET Framework
  • C++语言:C语言基础上增加了类机制,面向对象,高效
  • Java语言:面向对象,跨平台,通用的程序设计语言
  • Php:服务端执行、嵌入HTML文档的脚本语言,制作动态网页
  • Python:面向对象,解释型程序设计语言,通用的脚本语言
  • JavaScript 语言:为网页添加动态功能

2.1.4标记语言

非编程语言,不包含任何逻辑或算法

常见有:

  • HTML : HyperText Markup Language,超文本标记语言
  • XML : Extensible Markup Language,可扩展标记语言
  • XHTML :Extensible HyperText Markup Language,扩展的超文本标记语言

2.1.5 程序设计语言及其构成

数据成分: 常量、变量、全局量、局部量以及数据类型。

运算成分:程序语言允许使用运算符号及运算规则。

控制成分:顺序结构、选择结构、循环结构。

软件设计师-2.程序设计语言_第1张图片

下列语言中,()是一种通用的编程语言

A、HTML B、SQL C、Python D、Verilog

答案 C

通用的高级程序语言,一般都会提供描述数据、运算、控制和数据传输的语言成分,其中,控制成分中有顺序、()、循环结构。

A、选择 B、递归 C、递推 D、函数

2.2 表达式

前缀表达式 +ab

中缀表达式 a+b

后缀表达式(逆波兰式) ab+

软件设计师-2.程序设计语言_第2张图片

  • 将中缀表达式(a-b)*(c+5)转为后缀表达式

    首先注意计算的顺序 a-b 、c+5、最后是 *

    得到结果 ab- c5+ *

  • 后缀表达式的运算过程(转为中缀表达式)

    使用可以很方便的进行运算,运算过程如下:

    1. 遇到运算对象压入到栈里面
    2. 遇到运算符从栈中取出两个对象,并进行计算
    3. 将计算的结果再压入到栈里面
    4. 重复上述过程,直到结束

    上面的例子 (a-b)*(c+5),转为后缀表达式 ab- c5+ *

    1. 将a、b入栈
    2. 遇到运算符*-* ⇒ 进行 a-b 运算 ⇒ 计算结果x压入栈
    3. 将 c、5如入栈
    4. 遇到 + ⇒ 进行 c-5 运算 ⇒ 将计算结果 y 压入栈
    5. 遇到 * ⇒ 进行 x*y 运算 ⇒ 将计算结果 压入栈

算术表达式采用后缀式表示时不需要使用括号,使用()就可以方便地进行求值。a-b*(c+d)的后缀式为()。

A. 队列 B. 数组 C.栈 D. 广义表

A. a b c d- * +

B. a b c d * + -

C. a b – c * d +

D. a b c d + * -

答案 C 、D

2.3传值和传址调用

▶数据类型:

  • 数据值是否改变:
    • 常量:只有右值,值不能改变
    • 变量:有左值和右值,值可改变
  • 作用域:
    • 全局变量:存储空间一般不变
    • 局部变量:存储空间动态变化
  • 数据类型:
    • 基本类型: int、char、float、double、bool
    • 特殊类型:void
    • 用于定义类型:enum
    • 构造类型:数组、结构、联合
    • 指针类型:type *
    • 抽象数据类型:类类型

▶传值和传址调用

int FunctionExample( int x, float y)

传递方式 主要特点
传值调用 形参取的是实参的值,形参的改变不会导致调用点所传的实参的值发生改变
引用(传址)调用 形参取的是实参的地址,即相当于实参存储的是地址引用,因此其值的改变同时改变了实参的值。
参数的左值为地址,右值为具体的值。

▶传值调用

void swap( int x, int y) {
    int t;
    t=x;x=y;y=t;
    printf("%d %d", x, y);
}

main() {
    int a=3,b=4;
    swap(a,b);
    printf("%d %d", a, b);
}
  • 刚刚开始调用的时候 a=3, b=4, x=3, y=4
  • 执行完之后,a=3, b=4, x=4, y=3

▶传址调用

void swap( int *x, int *y) {
    int a, *t = &a;
    *t=*x;*x=*y;*y=*t;
    printf("%d %d", *x, *y);
}

main() {
    int a=3,b=4;
    swap(&a, &b);
    printf("%d %d", a, b);
}
  • 刚刚开始调用的时候 a=3, b=4, x=3, y=4
  • 执行完之后,a=4, 3=4, x=4, y=3

参数传递差异考题: 程序语言的传值调用机制是将()。

A、实参的值传递给被调用函数的形参

B、实参的地址传递给被调用函数的形参

C、形参的值传递给被调用函数的实参

D、形参的地址传递给被调用函数的实参

答案 A

传值和传址调用考题:函数fun1()、fun2()的定义如下所示,已知调用fun1 时传递给形参x的值是-5,若以引用调用(call by reference)的方式调用fun2,则函数fun1的返回值为 () ;若以值调用(call by value)的方式调用fun2,则函数fun1的返回值为 () 。

A. -18 B. -11 C. -8 D. 0

A. -18 B. -11 C. -8 D. 0

软件设计师-2.程序设计语言_第3张图片

答案: C、A

2.4 语言处理程序

语言处理程序:将高级语言转换成计算机可执行的机器语言,分为汇编、编译和解释程序

汇编程序:翻译由汇编语言编写的程序

解释程序:针对高级编写的源程序,直接解释执行源程序

编译程序:源程序翻译成目标语言程序,然后执行目标程序

软件设计师-2.程序设计语言_第4张图片

▶汇编程序

把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序。

汇编程序输入的是用汇编语言书写的源程序,输出的是用机器语言表示的目标程序。

汇编语言是为特定计算机或计算机系列设计的一种面向机器的语言,由汇编执行指令和汇编伪指令组成。

第一次扫描:定义符号的值并创建符号表 ST。汇编器中,利用了LC(地址跟踪计数器)。LC是汇编语言的指针,每识别出1个指令,LC就增加1。

第二次扫描:生成机器语言,产生目标程序。第一次扫描已经生成了符号表,第二次扫描时即可利用汇编器的“指令表”将对应的指令翻译成机器指令,同时将LC执行的内存地址填入机器码或数值。

▶解释程序

解释程序是一种语言处理程序。

在词法、语法和语义分析方面与编译程序的工作原理基本相同。

但在运行用户程序时,它直接执行源程序或源程序的内部形式(中间代码)。

解释程序并不产生目标程序,这是它和编译程序的主要区别

▶高级语言执行过程

用高级语言编写出的程序要能在计算机上运行时,由于计算机识别二进制,因此需要对源程序依次进行预处理编译链接的过程,才能确保源程序正确被执行。

软件设计师-2.程序设计语言_第5张图片

下面关于编译和解释的说法中,正确的是( )。 ①编译是将高级语言源代码转换成目标代码的过程 ②解释是将高级语言源代码转换为目标代码的过程 ③在编译方式下,用户程序运行的速度更快 ④在解释方式下,用户程序运行的速度更快

A.①③ B.①④ C.②③ D.②④

答案 A

一个应用软件的各个功能模块可采用不同的编程语言来分别编写,分别编译并产生(),再经过()后形成在计算机上运行的可执行程序。

A.源程序 B.目标程序 C.汇编程序 D.子程序

A.汇编 B.反编译 C.预处理 D.链接

答案 B、D

2.5 编译程序

▶编译过程

编译程序的功能是把某高级语言书写的源程序翻译成与之等价的目标程序(汇编语言程序或机器语言程序)。编译程序的工作可分为6个阶段,如下图所示,实际的编辑可能会将其中的某些阶段结合在一起进行处理。

软件设计师-2.程序设计语言_第6张图片

 软件设计师-2.程序设计语言_第7张图片

注意:在编译阶段,语义检查属于静态语义检查。动态语义检查是在运行阶段进行的。

▶词法分析

词法分析:从左到右逐个扫码源程序中的字符,识别其中的关键字(或保留字)、标识符、常数、运算符、分隔符(标点符号和括号)等

例:VAR X,Y,Z: real;

​ X:=Y+Z*60;

语法分析:

  1. 保留字 VAR
  2. 标识符 X
  3. 逗号 ,
  4. 标识符 Y
  5. 逗号 ,
  6. 标识符 Z
  7. 冒号 :
  8. 标识符 real
  9. 分号 ;
  10. 标识符 X
  11. 赋值号 :=
  12. 标识符 Y
  13. 加号 +
  14. 标识符 Z
  15. 乘号 *
  16. 整常数 60
  17. 分号 ;

▶语法分析

语法分析:根据语法规则将单词符号分解成各类语法单位,并分析源程序是否存在语法上的错误。包括:语言结构错误if...end不匹配缺少分号括号不匹配表达式缺少操作数等。

▶语义分析

语义分析:进行类型分析和检查,主要检测程序是否存在静态语义错误。包括:运算符和运算类型不符合,如取余时用浮点数

▶出错处理

  • 静态错误:
    • 编译时所发现的程序错误(编译正确的程序没有静态错误)
    • 分为语法错误和静态语义错误
    • 语法错误包括:单词拼写错误、标点符号错误、表达式中缺少操作数、括号不匹配等有关语言结构上的错误。
    • 静态语义错误:运算符和运算类型不符合等错误。
  • 动态错误:
    • 发生在程序运行时(程序可通过编译)
    • 也叫动态语义错误
    • 包括:陷入死循环、变量取零时做除数、引用数组下标越界等错误。

1.在对源程序进行编译的过程中,( )是正确的顺序。

A. 语义分析、语法分析、词法分析

B. 语法分析、词法分析、语义分析

C. 词法分析、语法分析、语义分析

D. 词法分析、语义分析、语法分析

答案 C

2.编译过程中,语法分析不能( )。

①去除源程序中的注释

②识别记号(单词、符号)

③识别结构不正确的语句

④识别含义不正确的语句

A.①② B.①③ C.③④ D.②④

答案 C

3.某C语言程序中有表达式x%m(即x被m除取余数),其中,x为浮点型变量,m为整型非0常量,则该程序在()时会报错,该错误属于()错误。

A.编译 B.预处理 C.编辑 D.运行A.逻辑 B.语法 C.语义 D.运行

答案 A, C

2.6 有限自动机和正规式

2.6.1正规式

正规式:由正规文法转换而来,通常正规文法等价于正规式。

文法产生式 正规式
规则1 A→xB, B→y A=xy
规则2 A→xA|y

A=x*y

规则3 A→x, A→y A=x|y

*表示可以出现0次或任意多次

x|y表示可能x、也可能是y

正规式 正规集
ab 符号串ab构成的集合

a|b

字符串a、b构成的集合

a* 由0个或多个a构成的符号串集合

(a|b)*

所有字符a和b构成的串的集合

a(a|b)*

a为首字符的a、b字符串集合

(a|b)*abb

以abb结尾的a、b字符串的集合

  • ab:只有一种情况,就是 ab
  • a|b:有两种情况,a或者b
  • a*:有无数种情况

1.表示"以字符a开头且仅由字符a、b构成的所有字符串"的正规式为()。

A.a*b* B.(alb)*a C.a(alb)* D.(ab)*

答案:C

2.6.2 正规式与有限自动机的状态转换

正规式与有限自动机的状态转换图的关系

软件设计师-2.程序设计语言_第8张图片

1.下图所示的有限自动机中,s0是初始状态,s3为终止状态,该自动机不能识别 ( ) 。

软件设计师-2.程序设计语言_第9张图片

A.abab B.aaaa C.babb D.abba

答案 A

2.正规式(ab|c)(0|1|2)表示的正规集合中有( ) 个元素,( ) 是该正规集合中的元素。

A.3 B.5 C.6 D.9

A.abc012 B.a0 C.c02 D.c0

答案 C、D

分析:(ab|c)(0|1|2)表示有如下几种:

  • ab0、ab1、ab2
  • c0、c1、c2

所以一共有6个元素

3.下图是一个有限自动机的状态转换图(A为初态、C为终态),该自动机识别的字符串集合可用正规式 ()来表示。

软件设计师-2.程序设计语言_第10张图片

A.(1|2)*00 B.0(1|2)*0 C.(0|1|2)* D.00(1|2)*

答案 B

2.6.3 有限自动机

有限自动机是在词法分析阶段使用的,它分为确定的有限自动机(DFA)和非确定的有限自动机(NDFA)

2.6.3.1 确定的有限自动机(DFA)

任何一个有穷的序列,经过有穷步转移后,都能落到一个具体的状态上,有穷自动机能够判断是接受还是拒绝。

DFA的定义

DFA定义,M = ( S, ∑, f, q₀, Z ),其中

  • S:有穷状态集

  • ∑:输入字母表;

  • f :S × ∑ → S 转移函数,表示一个状态的后续状态有若干个

    (S × ∑* → S 转移函数,扩展转移函数)

  • q₀ ∈ S :初始状态

  • Z ⊆ S :接受状态(终结状态)集合

L(M) = { w ∈ ∑* | f(q₀,w) ∈ Z }

2.6.3.2 非确定的有限自动机(NFA)

确定的有限自动机,它所有的状态的下一个状态是唯一确定的。

非确定的有限自动机的下一个状态是可以不唯一确定

  • ε移动:不需要任何输入符号,就可以从一个状态转到另一个状态。例如下图的 q2 可以不输入符号直接转成 q3
  • 多种选择(含0种选择):比如下图的中 q1状态下,输入1时可以转成q2,也可以原地不动(2种选择);q3状态下输入0,无路可走,没有选择(0种选择)。软件设计师-2.程序设计语言_第11张图片

非确定型N1及推导过程

  • ε移动和多种选择产生不同备份。
  • 无法移动时,该备份就小时
  • 有一个备份接受,整个计算就接受

第一步,首先是处于初始状态(q1),控制器指向$

软件设计师-2.程序设计语言_第12张图片

第二步,根据状态转换图,在 q1状态读取1后,状态可以转换为 q1q2,同时在q2状态可以通过ε移动直接到状态q3。产生了3个备份。

软件设计师-2.程序设计语言_第13张图片

第三步,根据状态转换图,对三个备份分贝进行读1操作

  • 第一个备份(在q2状态)读1之后,发现是无选择的,所以该备份消失。

  • 第二个备份(在q1状态)读1,与第二步操作出来的结果一样,有三个备份。软件设计师-2.程序设计语言_第14张图片

  • 第三个备份(在q3状态)读1,就会进入到状态q4软件设计师-2.程序设计语言_第15张图片

  • 最终第三步读取完成后,产生了4个备份软件设计师-2.程序设计语言_第16张图片

第四步,根据状态转换图,对四个备份分贝进行读0操作

  • 第一个备份(在q2状态)读0之后,只有一种选择,进入到状态q3
  • 第二个备份(在q1状态)读0之后,只有一种选择,还是在状态q1
  • 第三个备份(在q4状态)读0之后,只有一种选择,还是在状态q4
  • 第四个备份(在q3状态)读0之后,无选择,备份消失。
  • 最终第四步读取完成后,产生了3个备份软件设计师-2.程序设计语言_第17张图片

第五步,根据状态转换图,对三个备份分贝进行读0操作

  • 第一个备份(在q3状态)读1之后,只有一种选择,进入到状态q4
  • 第二个备份(在q1状态)读1之后,与第二步操作出来的结果一样,有三个备份。。
  • 第三个备份(在q4状态)读1之后,只有一种选择,还是在状态q4,与第一个备份结果相同,值保留一个。
  • 最终第四步读取完成后,产生了4个备份软件设计师-2.程序设计语言_第18张图片

第六步,读取到$判断读取结束,此时一共有四个备份,其中有一个指向了q4状态,所以"1101"是被非确定的有限自动机N1接受。

非确定的有限自动机 比 确定的有限自动机,自动机本身变简单了,因为它减少了状态数。但是对于计算的分析就变得复杂了,因为它带有不同的备份。

即 确定的有限自动机 描述复杂,分析简单;非确定的有限自动机 描述简单,分析复杂。

▶非确定型N1计算-计算树

软件设计师-2.程序设计语言_第19张图片

▶N1接受的语言

L(N1) = { w | w包含子串101或11 }

例子

L(N2) = { w | w倒数第三个字母为1 }

∑ = { 0,1 }

非确定型:猜想倒数第3个字母

软件设计师-2.程序设计语言_第20张图片

确定型:猜想倒数第3个字符

  • 首先确定最后是3个字符,一共有下面8种情况:000、100、010、110、001、101、011、111软件设计师-2.程序设计语言_第21张图片

  • 它们之间的转换关系图软件设计师-2.程序设计语言_第22张图片

  • 确定初始状态为 000,结束状态为:100、110、101、111软件设计师-2.程序设计语言_第23张图片

通过例子我们可以发现,确定型有限自动机比非确定型有限自动机复杂的多。确定型自动机是可以和计算机硬件对应起来的。非确定型是一个概念上的突破,它只是为了分析问题方便,而没有真实的硬件与之对应。

NFA的定义

N = ( S, ∑, f, q₀, Z ),其中

  • S:有穷状态集
  • ∑:输入字母表; ( ∑ε = ∑ ∪ {ε} ,对普通字母表做扩充,增加了ε(空) )
  • f :S × ∑ε → P(S) 转移函数,表示一个状态的后续状态有多个
  • q₀ ∈ S :初始状态
  • Z ⊆ S :接受状态(终结状态)集合

NFA与DFA的区别:可读取ε;状态读取一个输入,经过转换函数后,会有多个后续状态,后续状态是不确定的。

▶NFA的状态表

N = ( S, ∑, f, q₀, Z );S= { q1, q2, q3, q4 };∑= { 0,1 };q₀ = q1; Z= { q4 }

软件设计师-2.程序设计语言_第24张图片

NFA计算的形式定义

N = ( S, ∑, f, q₀, Z ),

  • 输入 w = w₁w₂...wₘ

计算:状态序列 r₀r₁r₂...rₘ

  • q₀ = r₁
  • qᵢ₊₁ ∈ f(rᵢ , wᵢ₊₁ ) (i=0,1,...,m-1)

接收计算

  • rₘ ∈ Z

M接受w:存在接受计算

  • L(M) = { x | M接受x }

例如上面 1101 的计算树例子

软件设计师-2.程序设计语言_第25张图片

它一共有7个计算式:

  1. q1,q1,q1,q1,q1
  2. q1,q1,q1,q1,q2
  3. q1,q1,q1,q1,q2,q3
  4. q1,q1,q2,q3
  5. q1,q1,q2,q3
  6. q1,q2
  7. q1,q2,q3,q4,q4

其中发现计算式7最后的状态是接受的,所以该有限自动机可接受 1101

习题:某确定性有限自动机(DFA)的状态转换图如下图所示,令 d= 0|1|2|...|9,则以下字符串中, 能被该 DFA 接受的是 ( ) 。

软件设计师-2.程序设计语言_第26张图片

A、3857 B、1.2E+5 C、-123.67 D、0.576E10

解答:

自动机M识别一个字符串的过程是从开始状态出发,根据字符串中的字符依次进行状态转换,若能到达终态且字符串结束,则该字符串可被自动机M识别。

考查题目中的选项,3857的识别过程是状态0→状态 1→状态 1→状态1,状态1不是终态;

字符串1.2E+5中的“+”不能识别;

字符串0.576E10的识别过程是状态0→状态 1→状态5→状态6→状态6,在状态6下不能识别E

字符串123.67的识别过程是状态0→状态4→状态1→状态1→状态5→状态6→状态6,因此该字串符可被题中的自动机识别。

2.6.3.3 非确定有限自动机的确定化

前提知识

ε(读法 艾普西隆

  1. 状态集的 ε-闭包: 状态集 I 中的任何状态 s 经任意条 ε 狐而能达到达的所有状态的集合,定义为状态集 I 的 ε-闭包,表示为 ε_closure(I)

  2. 状态集的 a 狐转换: 状态集 I 中的任何状态 s 经一条 a 狐 而能到达的所有状态的集合,定义为状态集 I 的a 狐转换,表示为 move(I,a)

    对于任意 NFA M=(S, ∑, f, q₀, Z) , I ⊆ s, a ∈ ∑ 不妨设 I = {s1,s2,...,sj},则 move(I,a) = f(s1,a) ∪ f(s2,a) ∪ ... ∪ f(sj,a)

  3. 状态机的a狐转换的闭包 Iₐ = ε_closure( move(I,a) )

    例如:有下图所示的NFA软件设计师-2.程序设计语言_第27张图片

  • 对于 I = {0},ε_closure(I) = ε_closure( {0} ) = {0,1,2,4,7}

  • 同理,若 I = {2,3},ε_closure(I) = ε_closure( {2,3} ) = {1,2,3,4,6,7}

  • 令A={0,1,2,4,7},则move(A,a)={3,8} ,move(A,b)={5}

    Iₐ = ε_closure({3,8}​​​​​​​) = { 1,2,3,4,6,7,8 } ,Ib = ε_closure({5}​​​​​​​) = {1,2,4,5,6,7}

注意:状态集 I 的ε-闭包还要包含自身 。

NFA 转换为 DFA N

设 NFA M=(S, ∑, f, s0, Z),与之等价的 DFA N=(S’, ∑, f‘, q0, Z’),用子集法将非确定的有限自动机确定化的步骤如下:

  1. 求出 DFA N 的初态 q0 ,即令q0 = C,此时 对于每个输入a(a∈∑),令 T=f({sᵢ₁ , sᵢ₂ , ... , sᵢₘ} , a) ,qj = ε_closure( T ) 近包含 q0,且没有标记

    s0为NFA 的初态

  2. 对于 S’ 尚未标记的 qi = {sᵢ₁ , sᵢ₂ , ... , sᵢₘ},sᵢⱼ ∈ S (j = 1 , ... , m),进行以下处理

    • 标记 qj,以说明该状态已经经过计算

    • 对于每个输入a(a∈∑),令 T=f({sᵢ₁ , sᵢ₂ , ... , sᵢₘ} , a) ,qj = ε_closure( T )

当状态为{sᵢ₁ , sᵢ₂ , ... , sᵢₘ}时,输入 a(a是∑集合中的一个)转换成T,DFA N的子集 qj 为ε_closure( T )

  • 若qj不在 S' 中,则将 qj 作为一个为佳标记的新状态添加到 S',同时把状态转换函数 f'(qi , a) 添加到 DFA M 中
    1. 重复步骤2,直到 S' 中不在有未标记的状态时为止。
  1. 令 Z‘ = {q|q∈S’ 且 Z≠∮ }

上面的概念有点抽象,我们举例说明

已知一个识别正规式 ab*a的非确定有限自动机,其状态转换图如下所示,用子集法将其转换为 DFA N。

软件设计师-2.程序设计语言_第28张图片

读题可知,NFA = (S, ∑, f, s0, Z),S = {0,1,2,3,4,5}, ∑ = {a,b}, s0 = 0,Z = {5}

  1. 先求出初态 q0 = ε_closure( s0 ) = ε_closure( {0} ) = {0}。 q0 = {0}。

  2. 根据状态图和算法步骤2,求解 DFA N 的各个状态过程如下

    1. ε_closure( move(q0,a) )=ε_closure( move({0},a) ) =ε_closure( {1} )={1,2,4} ,将*{1,2,4}记为q1*
    2. ε_closure( move(q0,b) )=ε_closure( move({0},b) ) =ε_closure( {} )={};
    3. ε_closure( move(q1,a) )=ε_closure( move({1,2,4},a) ) =ε_closure( {5} )={5} ,将*{5}记为q2*(q2为终态,因为5为NFA 的终态)
    4. ε_closure( move(q1,b) )=ε_closure( move({1,2,4},b) ) =ε_closure( {3} )={2,3,4} ,将*{2,3,4}记为q3*
    5. ε_closure( move(q2,a) ) =ε_closure( {} )={} ;
    6. ε_closure( move(q2,b) )=ε_closure( {} )={}
    7. ε_closure( move(q3,a) )=ε_closure( move({2,3,4},a) ) =ε_closure( {5} )={5} ,即q2
    8. ε_closure( move(q3,b) )=ε_closure( move({2,3,4},b) ) =ε_closure( {3} )={2,3,4} ,即q3

    此时已经没有新的状态了,算法可以终止,得出的 DFA N 图如下所示软件设计师-2.程序设计语言_第29张图片

DFA 最简化

先了解几个概念:

  1. 多余状态:对于一个状态Si,若从开始状态出发,不可能到达改状态Si,则Si为多余(无用)状态。

  2. 死状态:对于一个状态Si,对于任意输入符号a,若转到它本身后,不可能从它到达终止状态,则称Si为死状态。 都称为无关状态

  3. 等价状态:若Si为自动机的一个状态,我们把从Si出发能导出的所有符号串的集合记为L(Si)。 设有两个状态Si和Sj,若有L(Si)=L(Sj),则称Si和Sj是等价状态。

  4. 可区别状态:自动机中两个状态Si和Sj,如果它们不等价,则称它们可区别。

  5. 两个状态(Si和Sj)等价的判断条件:

    • 状态Si和Sj必须同时为终止状态同时为非终止状态。即终止状态和非终止状态是可区别的。

    • 状态Si和Sj对于任意输入符a∈Σ,必须转到等价的状态里,否则Si和Sj是可区别的。

      状态Si 任意输入符a∈Σ 可以转化成 Sj

      状态Sj 任意输入符a∈Σ 可以转化成 Si

DFA的化简算法:对于DFA M=(S,Σ,f,S0,Z)

  1. 首先将DFA的状态集进行初始化,分成Π=(Z,S-Z);

  2. 用下面的过程对Π构造新的划分Π new

    for (Π中每个组G) do    //每个组都是一个状态集
    begin
       把G划分成小组;
       G中的任意两个状态Si和Sj在同一组中,当且仅当对于Σ中任意输入符号a ,Si和Sj的a转换是到同一组中,move(Si,a) ∈Gi ,move(Sj,a) ∈Gi;
       这样,只要Si和Sj的a转换是到【不同的组】中,则说明Si和Sj是可区别的,可进行划分。在Π new中用刚完成的对G的划分代替原来的G。
    end ; 
    Π := Π new;
  3. 重复执行(2),直到Π中每个状态集不能再划分(Π new= Π)为止;

  4. 合并等价状态 ,在每个G中,取任意状态作为代表,删去其它状态;

  5. 删去无关状态,从其它状态到无关状态的转换都成为无定义。

举例:软件设计师-2.程序设计语言_第30张图片

  1. 首次划分: Π0=({2,3,4,5},{0,1})
  2. 在G={2,3,4,5}中:
    • f(2,a)=1,f(4,a)=0 (转向终态集{0,1}); f(3,a)=3,f(5,a)=5(转向非终态集{2,3,4,5})
    • {2,3,4,5} 中的元素转到了不同的组中,故{2,4}和{3,5}是可区别的,得Π1=({2,4},{3,5},{0,1});
  3. 在G={2,4}中
    • f(2,a)=1,f(4,a)=0(转向终态子集) ;
    • f(2,b)=3, f(4,b)=5(转向非终态子集{3,5})
    • {2,4}对输入a,转换到同一组;对于输入b也是转换到同一组。所以不可区别,不再进行划分;
  4. 考察G={3,5}
    • f(3,a)=3,f(5,a)=5(转向非终态子集{3,5})
    • f(3,b)=2,f(5,b)=4(转向非终态子集{2,4}),
    • {3,5}对输入a,转换到同一组;对于输入b也是转换到同一组。所以不可区别,不再进行划分;
  5. 考察G={0,1}
    • f(0,a)=f(1,a)=1(转向终态集{0,1});
    • f(0,b)=2,f(1,b)=4(转向非终态子集{2,4}),
    • {0,1}对输入a,转换到同一组;对于输入b也是转换到同一组。所以不可区别,不再进行划分;
  6. 进一步进行考察,可以发现每个子集都不能再划分了;
  7. 消去等价状态:{0,1}用0表示,{2,4}用2表示,{3,5}用3表示
  8. 去掉无关状态,因DFA M’中没有无关状态,所以下图即为最后结果。软件设计师-2.程序设计语言_第31张图片

正规式转换成NFA

通过下面的对应法则将正规式转换成NFA

软件设计师-2.程序设计语言_第32张图片

例如 构造与正则表达式 (ab)*(a*|b*)(ba)*等价的NFA,构造过程如下图所示

软件设计师-2.程序设计语言_第33张图片

2.7 习题

程序设计语言章节习题

题1

下面关于编程语言的各种说法中, ( ) 是不正确的。

A.逻辑型语言适用于书写自动定理证明

B.Smalltalk、C++、Java、C#都是面向对象语言

C.函数型语言适用于人工智能领域

D.由于C语言程序是由函数构成的,因此它是一种函数型语言

​ 按照程序设计范型的分类,程序设计语言基本上可以分为命令式程序设计语言、函数式程序设计语言、面向对象程序设计语言和逻辑程序设计语言。

命令式程序设计语言基于动作的语言,最典型的动作就是赋值。命令式程序设计语言的代表有 FortranPascalC语言等。

​ 函数是一种应对规则(映射),使定义域中每个元素和值域中唯一的元素相对应。函数式语言是一类以λ演算为基础的语言,主要用于人工智能领域,其代表有LispML等。

面向对象程序设计语言中最核心的东西是对象和类的概念。面向对象的三个核心概念是继承、封装、多态。面向对象程序设计语言的代表有C++SmallTalkJava等。

逻辑程序设计语言是一类以形式逻辑为基础的语言,其代表是建立在关系理论和一阶谓词理论基础上的Prolog。Prolog 有很强的推理功能,适用于书写自动定理证明、专家系统和自然语言理解等问题的程序。

所以答案是 D

题2

序言性注释是指在每个程序或模块开头的一段说明,起辅助理解程序的作用,一般包括:程序的表示、名称和版本号,程序功能描述,接口与界面描述,输入/输出数据说明,开发历史,与运行环境有关的信息等。下列叙述中不属于序言性注释的是()。

A.程序对硬件、软件资源的要求

B.重要变量和参数说明

C.嵌入在程序中的SQL语句

D.程序开发的原作者、审查者、修改者、编程日期等

答案 C

题6

确定有限自动机和不确定有限自动机。那么确定的有限自动机A与不确定有限自动机B等价,则()。

A.A与B的状态个数相等。

B.A与B可识别的记号完全相同。

C.B能识别的正规集是A所识别正规集的真子集。

D.A能识别的正规集是B所识别正规集的真子集。

对于任一个非确定有限状态自动机M,都可以构造其对应的确定有限自动机M',使这两个有限自动机接收相同的字符串集合 L(M') = L(M)。

所以答案选择 B。

题9

关于以下描述错误的是()。

A. 高级语言都是用接近人们习惯的自然语言和数学语言作为语言的表达形式。

B.计算机只能处理由0、1的代码构成的二进制指令或数据

C.每一种高级语言都有它对应的编译程序

D.C语言源程序经过C语言编译程序编译之后生成一个后缀为 EXE 的二进制文件

​ 由于高级程序设计语言具有可读写、可理解性好等特点,这就要求高级程序设计语言接近人们习惯的自然语言和数学语言作为语言的表达形式,选项A的说法正确。

​ 在计算机中,机器可以接受和处理的只能是由0和1组成的二进制代码,用高级语言编写的程序都需要经过编译和连接,使其转化为二进制代码才能被机器执行。因此选择B的说法正确。

​ 由于高级语言编写的程序都需要经过编译和连接,才能被计算机执行,因此每一种高级语言都有它对应的编译程序,C选项的说法正确。

C语言源程序经过C语言编译程序编译之后生成后缀为 OBJ 的二进制文件(称为目标文件);最后要由“连接程序”把此 OBJ 文件与C语言提供的各种库函数连接起来生成一个后缀为 EXE 的二进制文件。因此,选项D的说法不正确。

答案是 D。

题10

以下关于编译系统对某高级语言进行翻译的叙述中,错误的是()。

A.不同的高级程序语言可以产生同一种中间代码

B.在机器上运行的目标程序完全独立于源程序

C.目标代码生成阶段的工作与目标机器的体系结构相关

D.经过反编译,可以将目标代码还原成源代码

​ 首先要了解源程序、中间代码、目标代码的关系。其中源程序是指高级语言编写的程序,将源程序经过编译,就可以得到中间代码并最终得到目标代码,目标代码就是可以在具体机器上执行的代码,这是源程序和编译程序都不参与目标程序的执行过程,所以在机器上运行的目标代码是完全独立于源程序的。

​ 另外,目标代码是在机器上执行的代码,所以它的生产与目标机器的体系结构相关 。

​ 中间代码是一种简单且含义明确的记号系统,与具体的机器无关,可以有若干种形式。可以将不同的高级程序语言翻译成同一种中间代码,另外由于与具体的机器无关,使用中间代码有利于进行与机器无关的优化处理,以及提高编译程序的可移植性。

​ 编译是将高级语言程序翻译成机器语言程序(即目标代码),反编译是编译的逆向过程。反编译通过不能把可执行文件还原成高级语言源代码,只能转换成功能上等价的汇编程序。

所以答案选择 D。

题11

对于以下编号为①、②、③的正规式,正确的说法是()。

(a*b*)*b (a|b)*b (b*|a*)*b

A.正规式①、②等价

B.正规式①、③等价

C.正规式②、③等价

D.正规式①、②、③互不等价

答案 C

题12

集合 L ={aᵐbᵐ|m>0} ___。

A.可以用正规式“a*b*”表示

B.不能用正规式表示,但可用非确定的有限自动机识别

C.可用正规式“aᵐbᵐ”表示

D.不能用正规式表示,但可用上下文无关文法表示

​ 用正规式定义一些简单的语言,但是很多复杂一些的语言不能用正规式表达。例如,正规式不能用于描述配对或嵌套结构,具体的例子有由配对括号构成的串的集合不能用正规式描述语句的嵌套结构也不能用正规式描述;还有,重复的串也不能用正规式表示,如集合{wcw|w是a和b的串}不能用正规式描述。

​ 正规式只能表示给定结构的固定次数的重复或没有指定次数的重复。在本题中,指定了重复的次数m,但是m又不是固定的,所以也不能使用正规式表示。

​ 有限状态自动机识别的语言是正规语言。对于每个非确定的有限自动机,都有一个与其等价的正规式。因此,题目中的集合既然不能使用正规式表达,也就不能用非确定的有限自动机识别。

​ 上下文无关文法的描述功能比正规式更强,正规式可以描述的每种结构都可以用上下语言无关文法来描述,但反之不然。上下文无关文法能表示次数不固定的重复。因此本体答案选 D。

题13

程序语言的大多数语法现象可用上下文无关文法描述。对于一个上下文无关文法G=(N,T,P,S),其中N是非终结符号的集合,T是终结符号的集合,P是产生式集合,S是开始符号。令集合V=N∪T,那么G所描述的语言是()的集合。

A.从S出发推导出的包含V和T中所有符号的串

B.从S出发推导出的包含V中所有符号的串

C.从S出发推导出的仅包含T中符号的串

D.T中所有符号组成的串

​ 对于一个上下文无关文法G=(N,T,P,S),如果它的产生式规则都取如下的形式,V∈w,这里V∈VN,w∈(VT ∪ VN)*。开始符号是一种特殊的非终结符号,而所谓终结符号是组成语言的基本符号,从语法分析的角度来看,终结符号是一个语言不能再进行分割的基本符号。上下文无关文法取名为“上下文无关”的原因就是因为字符V总可以被字符串w自由替换,而无需考虑字符V出现的上下文。

​ 在这到题里,V∈N∪T,根据上下文无关的特性,V总可以被字符串N∪T自由替换;但当v=N∪T时,由于非终结符的不唯一性,要构成等式成立,必须要N∪T中的符号串收缩为终结符,即都是T的集合。所以上下文无关方法G所描述的语言是从S触发推导出的仅包含T中符号的串的集合。

答案 C

题15

下图为一确定有限自动机(DFA)的状态转换图,图中的( ) 是可以合并的状态。软件设计师-2.程序设计语言_第34张图片

A.0和1 A.2和3 A.1和2 A.0和3

两个状态 s 和 t 如果同时满足下列两个条件,我们就称s和t是等价的:

​ 1)一致性:同时终态或同时非终态。

​ 2)蔓延性:从s触发读入某个a和从t输入读取某个a到达的状态等价。

可以合并的状态是指对所有可能的输入,其转换的状态均相同。 显然状态2和状态3是可以合并的。

答案 D

题20

下列叙述中正确的是()。

A. 算法的时间、空间复杂度与实现该算法所采用的程序设计语言相关

B. 面向对象程序设计语言不支持对一个对象的成员变量进行直接访问

C. 与汇编语言相比,采用脚本语言编程可获得更高的运行效率

D. 面向对象程序设计语言不支持过程化的程序设计,只支持面向对象程序设计

程序设计语言对抽象机制的支持程度不断提高:从机器语言,到高级语言,这个过程抽象程度越来越高,程序可读性越来越好,但其程序的执行效率越来越低。

面向对象程序设计语言引入了数据抽象和类的概念,即可支持过程化的程序设计,也可以支持面向对象的程序设计。其最大的特点有继承、封装和多态,其中它的封装特性决定了面向对象程序设计语言不支持对一个对象的成员变量被直接访问,否则就破坏了其封装性。

关于脚本语言的一些基本知识如下:

  • 脚本语言(JavaScript、VBScript等)是介于HTML和C、C++、Java、C#等编程语言之间的程序设计语言。HTML通常用于格式化的链接文本,而编程语言通常用于向机器发出一些列复杂的指令。
  • 脚本语言中也使用变量和函数,这一点与编程语言相似。与编程语言之间最大的区别是编程语言的语法和规则更为严格和复杂。
  • 脚本语言一般都有相应的脚本引擎来解释执行,是一种解释型语言,一般需要解释器才能运行。
  • 脚本语言一般以文本形式存在,类似一种命令。

编程语言是符号化的机器语言,一般情况下用汇编语言编写的程序比高级语言效率更高。根据脚本语言的以上特点,“采用脚本语言编程可获得更高的运行效率”是错误的。

本地答案 B。

题23

许多程序设计语言规定,程序中的数据都必须具有类型,其作用不包括()。

A.便于为数据合理分配存储单元

B.便于了解数据的取值范围

C.便于对参与表达式计算的数据对象进行检查

D.便于定义动态数据结构

程序设计语言规定,程序中的数据都必须具有类型,主要是考虑到了以下几个因素:

  • 确定了数据类型,这样就确定了该数据所需要占用的存储空间,便于系统为程序分配存储空间。
  • 确定了数据类型,就知道了该数据占几个字节,自然也就清楚了数据所能表示的数据范围。
  • 确定了数据类型,那么久确定了该数据能参加一些什么样的运算,如自加运算就不允许其操作数为浮点数。

所以答案选 D。

题24

以下关于程序设计语言的描述中,争取的是()。

A. 在C语言中,对指针变量进行算术运算是没有意义的。

B. 在C语言中,指针变量必须由动态产生的数据对象来赋值。

C. 在C语言中,变量和常量都具有类型属性。

D. 在C语言中,变量和常量都可以被赋值。

在C语言中,常量是指一旦确定后就不能再变的量,而变量则是在一个程序执行过程中,可以根据需要修改的量,是一个可改变的量。当然不管是常量还是变量,它们都有其类型属性,而变量的值允许修改因此可以被赋值,常量则不能赋值。

变量是内存单元的抽象用于在程序中表示数据。当变量存储的是内存单元地址时,称为指针变量,或者说指针变量指向了另一个变量。指针变量可以定义在函数或复合语句内,也可以定义在所有的函数之外,即可以是全局变量,也可以是局部变量。需要区分指针变量与指针所指向的变量,无论指针变量指向何种变量,其存储空间大小都是一样的。当指针变量指向数组中的一个元素时,对指针变量进行算法运算可以指向同一个数组中的其他元素。

所以答案是 C。

题27

下列程序语言,()最早是为了教学的目的开发而成的。

A. C语言

B. Fortran

C. Prolog

D. Pascal

Fortran 语言是第一个广泛应用于科学计算的高级语言。由一个主程序和若干个子程序组成,由于大部分代码都可以直接使用硬件结构实现,因此执行效率很高。

Pascal 语言最早是为了教学的目的开发而成的,拥有一些相当紧凑的进制,其语言的表达能力十分强。它引入了数据结构、过程等重要概念。常用的Delphi便是采用的Pascal语言语法规则。

C语言是通用的程序设计语言,提供了指针、数组、结构、联合等新的数据类型。它通过指针可以完成地址操作能力,因此是一种较低级的语言,能够编写出高效的程序。UNIX系统本身,以及其中大量的应用程序都是使用C编写的。

Prolog程序是以特殊的逻辑推理形式回答用户的查询。Prolog程序具有逻辑的简洁性和表达能力。实际应用上多用于数据库和专家系统。

你可能感兴趣的:(软考,软考,软件设计师)