跳到主要内容

系统软件

A-Level 计算机科学 · 知识点 16

本主题的视频课程 打开视频页面
14:02

资源、编译器与 RPN

打开浏览器、音乐播放器和游戏。你只有一个处理器——可能有几个核心——但它们似乎同时在运行。并且它们一起需要更多……

英语旁白 · 英中内嵌字幕

16.1

操作系统(OS)的功能

教学大纲
考生应能够: 注释与指导
展示对**操作系统(OS)**如何最大化资源利用的理解
描述用户界面隐藏硬件复杂性以面向用户的方式
展示对进程管理的理解 多任务处理和进程的概念;进程状态:运行中、就绪和阻塞;调度的必要性,以及不同调度例程的功能与优势(包括轮转法、最短作业优先、先来先服务、剩余时间最短);操作系统的内核如何作为中断处理器工作,以及中断处理如何用于管理低层调度
展示对用于内存管理的虚拟内存、分页和分段的理解 分页、虚拟内存和分段的概念;分页与分段的区别;页面替换方式;磁盘抖动是如何发生的

来源:Cambridge International 教学大纲

一台计算机有许多资源(CPU 时间、内存、磁盘、I/O)和许多程序争夺它们。OS 公平且高效地共享它们,使每个都被好好利用,系统保持响应:

OS 在程序之间共享 CPU 时间、内存、磁盘和输入/输出
OS 在程序之间共享 CPU、内存、磁盘和 I/O
  • 多任务(multi-tasking)——在进程之间快速切换 CPU,使几个看起来一次运行。
  • 内存管理(memory management)——给每个进程它需要的内存;当 RAM 用尽时用磁盘分页(paging)。
  • 假脱机(spooling)和缓冲——打印作业在磁盘上排队,所以 CPU 从不等打印机。
  • 缓存(caching)——把最近用过的磁盘数据保存在高速缓存(cache)/ RAM 中。
一个处理器和它的散热器
处理器是 OS 在争夺的任务之间共享的一个关键资源
内存模块(RAM)
OS 也管理内存(RAM),决定在它里面保留什么、把什么分页到磁盘
词汇 训练
English 中文 拼音
multi-tasking/ˈmʌlti ˈtæskɪŋ/ 多任务 duō rèn wù
paging/ˈpeɪdʒɪŋ/ 分页 fēn yè
spooling/ˈspuːlɪŋ/ 假脱机 jiǎ tuō jī
cache/kæʃ/ 高速缓存 gāo sù huǎn cún
16.1

用户界面

用户界面把硬件隐藏在友好的抽象之后:用户看到窗口、菜单和文件夹,而不是地址或扇区。在一个图标上点一下,使 OS 在磁盘上找到程序、分配内存、加载它并启动它。一个 CLI(命令行)对专家强大且可脚本化;一个 GUI(图形)更容易学。大多数系统两者都提供。

"描述硬件的复杂性对用户隐藏的两种方式。" (1) 用户用名字操作文件和文件夹,由 OS 把它们翻译成磁盘的磁道、扇区和块;(2) 用户用一次点击或一条命令运行程序,由 OS 装载它、分配内存并调度它,用户不需要知道任何地址;(3) 设备驱动程序让用户打印或保存而不必知道打印机或磁盘如何控制;(4) 图形界面用图标、窗口和菜单取代机器级命令。对学生的好处及例子:OS 使硬件无需技术知识即可使用,例如把文档的图标拖过去就能保存到 U 盘。

"说明 OS 如何最大化资源的利用。" 它调度处理器,使有进程就绪时处理器决不空闲;它管理内存,把内存分配给进程、回收并用虚拟内存扩展它;它管理输入和输出,用缓冲和假脱机使快慢设备的工作重叠;它管理存储,记录空闲空间和文件。每一点都要点名一种资源以及 OS 对它做什么。

16.1

进程管理

一个进程(process)是执行中的一个程序——它的代码、当前状态、内存和打开的文件。

调度

调度器(scheduler)选择哪个就绪进程接下来运行,以及运行多久:

  • 轮转(round robin)——每个进程得到一个固定的时间片(time slice),然后去到队列的后面。
  • 先来先服务;最短作业优先;最短剩余时间(shortest remaining time,运行剩余工作最少的作业);优先级;多级反馈队列。

权衡是响应性对吞吐量对公平性。

"描述多任务是什么意思以及它如何有益于进程管理。" 几个进程同时保存在内存中,处理器在它们之间切换得如此之快,以至于它们看起来在同时运行,每个轮流得到一份处理器时间。好处:当一个进程等待输入或输出时处理器决不闲置,所以吞吐量更高,用户可以同时在几个程序上工作。"解释调度的必要性。" 进程多于处理器,所以必须决定哪个进程接下来运行以及运行多久;调度确保每个进程都取得进展、处理器被充分利用、响应时间可接受,并且优先级得到尊重。

同样三个作业的两条时间线:先来先服务先运行长作业,短作业排在它后面等待;最短作业优先先运行短作业,把平均等待时间从 6.7 降到 2.7 个单位
同样的工作换个顺序:最短作业优先先把短作业解决掉,所以大多数作业等得更少,代价是长作业可能永远等下去

调度例程,按考试要求的描述方式。

例程 功能 优点 缺点
先来先服务(FCFS) 进程按到达就绪队列的顺序运行,各运行到结束 简单;每个进程都轮到,没有饥饿 一个长进程拖住它后面所有的短进程;响应差
最短作业优先(SJF) 估计运行时间最短的就绪进程下一个运行,直到结束 平均等待时间最小;许多短作业很快完成 运行时间必须预先知道;长作业可能永远不运行(饥饿)
最短剩余时间(SRT) SJF 的抢占式(pre-emptive)版本:若新到的进程剩余时间少于正在运行的,它就接管 短进程得到更快的服务;吞吐量好 更多上下文切换;长作业可能被反复打断而饥饿
轮转(RR) 每个就绪进程轮流得到固定的时间片;到期后进程回到队尾 公平;每个进程在有限时间内响应,适合交互使用 上下文切换开销;时间片太短浪费时间,太长则延误其他进程
优先级 优先级最高的就绪进程先运行 重要或时间紧迫的工作先做 除非优先级随时间提升,低优先级进程可能饥饿

例题。 三个进程同时到达,CPU 时间分别为 8、4 和 2 ms。比较 FCFS(按到达顺序 A、B、C)和最短作业优先下的平均等待时间。

FCFS(先来先服务):A等待0,B等待8,C等待12;平均等待$(0 + 8 + 12)/3 = 6.7\ \text{ms}$。SJF(短作业优先)按C、B、A顺序执行:C等待0,B等待2,A等待6;平均等待$2.7\ \text{ms}$。总工作量同为14毫秒,区别仅在于调度顺序影响各任务等待时长。采用2毫秒时间片进行轮转调度时,A、B、C在第一6毫秒内各获得一次执行机会,因此C于6毫秒完成,B于10毫秒完成,A于14毫秒完成:这种方式响应最快,但平均完成时间并非最优。

一个甘特时间线,显示 P1 然后 P2、P3、P4 从时间 0 到 39 一个接一个地运行,带一个图例给出每个进程的 CPU 突发时间
四个进程的先来先服务调度
轮转调度显示为一个时间线:P1、P2、P3 各依次得到一个固定的时间片,然后循环重复,在它们之间共享 CPU
轮转:每个进程依次得到一个固定的时间片,然后下一个运行(不像先来先服务)

进程状态

一个进程是新建(new)、就绪(ready,等待 CPU)、运行(running)、阻塞(blocked,等待 I/O 或一个锁),或终止(terminated)。当它的时间片结束时它从运行 → 就绪;当它请求 I/O 时它从运行 → 阻塞;当 I/O 完成时它从阻塞 → 就绪。

一个状态图:新建到就绪(准入)、就绪到运行(调度器分派)、运行到就绪(中断或超时)、运行到阻塞(请求 I/O)、阻塞回到就绪(I/O 完成)、运行到终止(退出)
一个进程在新建、就绪、运行、阻塞和终止状态之间移动

三个状态以及进程为什么转移。 *运行:*进程占有处理器。*就绪:*它可以运行但在等待处理器。*阻塞:*在其他事件发生之前它不能运行。每种转移的原因,考试会逐个问:运行到就绪,当它的时间片用完,或当一个更高优先级的进程变为就绪并抢占它(一次中断);运行到阻塞,当它请求输入或输出,或等待某个资源或另一个进程;阻塞到就绪,当它等待的 I/O 完成(由中断通知);就绪到运行,当调度器派遣它。阻塞的进程决不能直接进入运行:它必须先变为就绪。

进程控制块与上下文切换

对每个进程,OS 保存一个进程控制块(process control block,PCB)——保存的程序计数器、寄存器、状态和内存信息。

一次上下文切换保存进程 A 的状态(它的 PCB)并加载进程 B 的
一次上下文切换保存一个进程的状态并加载另一个的
  • 一次上下文切换(context switch)挂起一个进程并启动另一个:它把状态保存进一个 PCB 并从另一个恢复它。这个小代价在每次切换时付出。
  • 内核(kernel,OS 的核心)充当一个中断处理程序(interrupt handler)。当一个设备或定时器发起一个中断时,中断处理(interrupt handling)保存运行中的进程并运行正确的例程——这就是驱动底层调度的东西。

"概述内核如何充当中断处理程序"(两分)。 中断发生时,内核保存正在运行进程的状态(它的寄存器和程序计数器,存入进程控制块),识别中断的来源和优先级,运行相应的中断服务例程,然后恢复被中断的进程(或一个更高优先级的进程),使执行继续。定时器就是这样结束时间片的,完成的 I/O 操作也是这样解除进程阻塞的。

进程间通信

进程是隔离的,所以 OS 提供进程间通信(inter-process communication):管道(pipes,一个程序的输出馈入另一个的输入)、共享内存(shared memory,几个进程可以用的一个区域),以及消息传递。

探索

一个进程的生命

点击绕一个进程经历的循环。它只在调度器挑选它时运行;需要 I/O 把它送到阻塞,完成它的时间片把它送回就绪——一圈又一圈直到它完成。

词汇 训练
English 中文 拼音
process/ˈprəʊses/ 进程 jìn chéng
scheduler/ˈʃedjʊlə/ 调度器 diào dù qì
round robin/raʊnd ˈrɒbɪn/ 轮转 lún zhuàn
time slice/taɪm slaɪs/ 时间片 shí jiān piàn
pre-emptive/priː ˈemptɪv/ 抢占式 qiǎng zhàn shì
blocked/blɒkt/ 阻塞 zǔ sè
process control block/ˈprəʊses kənˈtrəʊl blɒk/ 进程控制块 jìn chéng kòng zhì kuài
context switch/ˈkɒntekst swɪtʃ/ 上下文切换 shàng xià wén qiè huàn
kernel/ˈkɜːnl/ 内核 nèi hé
interrupt handler/ˈɪntərʌpt ˈhændlə/ 中断处理程序 zhōng duàn chǔ lǐ chéng xù
interrupt handling/ˈɪntərʌpt ˈhændlɪŋ/ 中断处理 zhōng duàn chǔ lǐ
inter-process communication/ˈɪntə ˈprəʊses kəˌmjuːnɪˈkeɪʃn/ 进程间通信 jìn chéng jiān tōng xìn
pipes/paɪps/ 管道 guǎn dào
shared memory/ʃeəd ˈmeməri/ 共享内存 gòng xiǎng nèi cún
16.1

虚拟内存、分页与分段

每个进程得到它自己的虚拟地址空间(virtual address space)——OS 映射到物理内存的一个干净、连续的地址范围。这给每个进程一个简单的空间,保护进程彼此隔离,并让总内存超过物理 RAM。

在分页中,虚拟空间被拆成固定大小的页(pages),物理内存被拆成同样大小的页框(frames)。一个页表把每个页映射到一个页框。若一个被访问的页不在 RAM 中——一个缺页(page fault)——OS 从交换文件(swap file)把它读进一个页框,若 RAM 满了就逐出另一个页。频繁的缺页导致抖动(thrashing,磁盘抖动),那里 OS 把它的大部分时间花在交换页而不是做有用的工作。

逻辑内存页通过一个页表映射到非连续的物理内存页框
分页把逻辑内存的每个页映射到物理内存的一个页框

在分段(segmentation)中,内存被拆成可变大小的逻辑段(代码、栈、堆),每个有它自己的权限。许多系统在段内使用分页。

可变大小的逻辑段(代码、堆、栈)通过一个大小和起始地址的段表映射到物理内存
分段用一个段映射表映射可变大小的段

"解释虚拟内存是什么意思"(三分)。 用辅助存储器(磁盘)扩展 RAM,使可用内存显得比物理内存大;进程的地址空间被分成页,只有当前需要的页保存在 RAM 中,其余在磁盘上等待;页按需要在 RAM 和磁盘之间交换,OS 把每个虚拟地址翻译成物理地址。OS 为什么需要它:正在运行的程序可能需要比安装的 RAM 更多的内存;它让更多(或更大)的程序同时运行;程序可以比物理内存大;内存得到高效利用,因为只有程序的活动部分占据 RAM。

分页对分段:考试要的区别。 分页把内存分成由硬件决定的固定大小的块(页和页框),不考虑程序的结构,映射对程序员不可见;分段把程序分成大小可变的逻辑单元(一个过程、一个数组、栈),其大小和边界跟随程序,所以一个段可以作为整体被保护或共享。"描述分段的过程":程序被拆成大小不同的段,每段给一个段号;段表记录每段在内存中从哪里开始、有多长;逻辑地址是段号加偏移量,OS 把偏移量加到该段的基地址上得到物理位置。

"解释磁盘抖动是什么意思"以及它何时发生。 磁盘抖动(disk thrashing)是页在 RAM 中换入换出如此频繁,以至于处理器花在搬页上的时间多于执行指令、系统几乎停顿的状态。它发生在 RAM 对正在运行的进程所需的页(它们的工作集)来说太小时:刚换出的页几乎立刻又被需要,于是被取回,又挤出另一个很快就要用的页,如此往复。进程太多,或程序以不可预测的方式访问内存,都会引起它;更多 RAM 或更少进程能治愈它。

探索

缺页时发生什么

逐步走过一次缺页。当程序接触一个不在 RAM 中的页时,操作系统悄悄地从磁盘取它并更新页表——所以程序看到的内存比物理存在的更多。

词汇 训练
English 中文 拼音
virtual address space/ˈvɜːtʃuːəl əˈdres speɪs/ 虚拟地址空间 xū nǐ dì zhǐ kōng jiān
pages/ˈpeɪdʒɪz/ 页 yè
frames/freɪmz/ 页框 yè kuāng
page fault/peɪdʒ fɒlt/ 缺页 quē yè
swap file/swɒp faɪl/ 交换文件 jiāo huàn wén jiàn
thrashing/ˈθræʃɪŋ/ 抖动 dǒu dòng
segmentation/ˌseɡmənˈteɪʃn/ 分段 fēn duàn
disk thrashing/dɪsk ˈθræʃɪŋ/ 磁盘抖动 cí pán dǒu dòng
16.2

翻译软件

教学大纲
考生应能: 注释与指导
说明解释器如何在不生成翻译版本的情况下执行程序
说明程序编译的各个阶段 包括词法分析、语法分析、代码生成和优化
说明如何使用语法图或**巴科斯-诺尔范式(BNF)**来表示语言的语法规则
说明如何使用**逆波兰表示法(RPN)**进行表达式求值

来源:Cambridge International 教学大纲

一个解释器(interpreter)同时翻译并运行源代码。对每条语句它读这行、做词法和语法分析、检查类型,然后执行该动作,并继续。错误被立即报告,它通常停止;不产生可执行文件。翻译每次运行都重做(更慢),但它给出快速的开发反馈并且是可移植的。

"解释解释器如何在不产生翻译版本的情况下执行程序"(三分)。 解释器一次取一条语句(一行),翻译(分析)它,并立即执行,然后再处理下一条;不创建或存储整个程序的翻译版本,所以每条语句每次执行都要翻译,包括循环的每一趟;若某条语句有错误,执行在那里停止并报告错误。这就是解释器适合开发和测试(错误在到达时被发现,修改可以立即试验)但运行成品程序较慢的原因。

词汇 训练
English 中文 拼音
interpreter/ɪnˈtɜːprɪtə/ 解释器 jiě shì qì
16.2

编译的各阶段

一个编译器(compiler)分阶段把源代码变成机器码(machine code):

  1. 词法分析(lexical analysis)——词法分析器把字符分组成词法单元(tokens,关键字、标识符、运算符、字面量),丢弃空白和注释。
  2. 语法分析(解析)(syntax analysis / parsing)——检查词法单元符合文法并构建一棵抽象语法树(abstract syntax tree)。一个遗漏的括号给出一个语法错误(syntax error)。
  3. 语义分析(semantic analysis)——检查程序说得通(变量已声明、类型匹配)。
  4. 代码生成(code generation)——遍历树并发出目标代码,选择寄存器和布局。
  5. 代码优化(code optimisation)——去除冗余的工作、折叠常量、为流水线重排。

输出是一个可执行文件。

编译的各阶段:源代码经过词法分析(词法单元)、语法分析(AST)、语义分析(检查)、代码生成和优化以产生一个可执行文件
编译的各阶段,从源代码到一个优化的可执行文件

各阶段的目的,用得分的措辞。 *词法分析:*去掉空白和注释;把源代码的字符转换成词法单元(关键字、标识符、运算符、常量),检查每一个在该语言中是否有效;把标识符登记到符号表(symbol table)中。*语法分析:*检查词法单元序列是否符合语言的文法(语法规则);构建解析树(抽象语法树);报告语法错误;类型检查和变量声明的检查有时归入语义分析。*代码生成:*把检查过的树转换成目标代码或机器码(可能经由中间代码),分配内存和寄存器。*优化:*使代码运行更快或占用更少内存,通过去除冗余指令、合并或简化计算、重组循环,而不改变程序的功能。配对题把每个阶段与这些描述之一配对。

探索

编译的各阶段

逐步走过一个编译器对你的源代码做什么。每个阶段把它的输出交给下一个——字符变成记号,记号变成一棵树,树变成优化的机器码。

词汇 训练
English 中文 拼音
compiler/kəmˈpaɪlə/ 编译器 biān yì qì
machine code/məˈʃiːn kəʊd/ 机器码 jī qì mǎ
lexical analysis/ˈleksɪkl əˈnæləsɪs/ 词法分析 cí fǎ fēn xī
tokens/ˈtəʊkənz/ 词法单元 cí fǎ dān yuán
syntax analysis (parsing)/ˈsɪntæks əˈnæləsɪs/ 语法分析 yǔ fǎ fēn xī
abstract syntax tree/ˈæbstrækt ˈsɪntæks triː/ 抽象语法树 chōu xiàng yǔ fǎ shù
syntax error/ˈsɪntæks ˈerə/ 语法错误 yǔ fǎ cuò wù
semantic analysis/səˈmæntɪk əˈnæləsɪs/ 语义分析 yǔ yì fēn xī
code generation/kəʊd ˌdʒenəˈreɪʃn/ 代码生成 dài mǎ shēng chéng
code optimisation/kəʊd ˌɒptɪmaɪˈzeɪʃn/ 代码优化 dài mǎ yōu huà
symbol table/ˈsɪmbl ˈteɪbl/ 符号表 fú hào biǎo
16.2

文法:BNF 与语法图

一个文法(grammar)说明哪些词法单元序列是有效的程序。

巴科斯-诺尔范式(Backus-Naur Form,BNF)是文本的。一个产生式(production rule)有这样的形式:

<symbol> ::= alternative1 | alternative2 | ...

每个候选是一个终结符(terminal)符号(字面文本)和非终结符(non-terminal)符号(其他规则名)的序列:

<digit>      ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<identifier> ::= <letter> | <identifier> <letter> | <identifier> <digit>

递归的第三条规则表达"一个字母后跟任意数目的字母或数字"。一个 IF 语句:

<if-statement> ::= IF <condition> THEN <statement> ENDIF
                 | IF <condition> THEN <statement> ELSE <statement> ENDIF

一个语法图(syntax diagram,铁路图)以图形显示同样的东西:非终结符用方框、终结符用圆角框、有效路径用箭头、重复用循环。两种记法是等价的。解析器用文法来判定一个程序是否有效。

一个赋值的铁路图:一个矩形标识符框、一个圆角的赋值符号框,然后一个矩形表达式框,从左到右连接
一个赋值语句的语法(铁路)图
三张语法图,分别定义字母、数字,以及以字母开头、后接任意多个字母或数字的标识符,旁边是表达完全相同文法的 BNF 规则,并给出有效和无效的例子
语法图和 BNF 规则说的是同一件事:一个选择变成用竖线分隔的候选,一个循环变成引用自身的规则

阅读考试图表。 每个图表定义一个非终结符;从入口到出口沿箭头追踪,所有可追溯的路径均为有效字符串。并排的方框表示选择(即一组替代方案);回环箭头表示“可重复任意次”;指向另一非终结符的方框表示“插入该规则允许的任何内容”。“说明该字符串无效的原因”要求用文字指出其违反的规则:9K作为变量无效,因为首字符必须是字母而非数字;JJ90作为密码无效,若规则仅允许数字前出现一个字母,或J不在所列字母集合中。始终将字符串与图表实际允许的字符集比对,而非现实语言规范。

根据图表编写BNF。 每个图表对应一条规则<name> ::= ...;替代项以|分隔;序列按符号顺序书写;重复通过递归实现(因BNF无循环符号):“一个或多个字母”写作<word> ::= <letter> | <letter><word>,“字母后跟零个或多个数字”写作<variable> ::= <letter> | <letter><digits>,其中<digits> ::= <digit> | <digit><digits>代表数字部分。

例题。 补全车辆登记号的 BNF:必须以两个字母(取自 A B C)开头,后接一位、两位或三位数字(取自 0 1 2)。

<letter>       ::= A | B | C
<digit>        ::= 0 | 1 | 2
<digits>       ::= <digit> | <digit><digit> | <digit><digit><digit>
<registration> ::= <letter><letter><digits>

AB12 有效;A12 无效(只有一个字母);AB1234 无效(四位数字);AD1 无效(D 不是列出的字母)。被要求加约束如"第三个字符也可以是符号"时,只给那个位置的规则加额外候选,并用单独的规则定义 <symbol>。

例题。 写出表达式的 BNF:表达式是一个变量,后接一个运算符,再接一个变量或一个数,其中变量是取自 a b c 的单个小写字母,运算符是 + 或 -。

<variable>   ::= a | b | c
<operator>   ::= + | -
<number>     ::= <digit> | <digit><number>
<expression> ::= <variable><operator><variable> | <variable><operator><number>

递归的 <number> 规则允许任意多位数字;<expression> 的两个候选覆盖定义中提到的两种情况。每个非终结符都放在尖括号里,每个终结符都不加。

词汇 训练
English 中文 拼音
grammar/ˈɡræmə/ 文法 wén fǎ
Backus-Naur Form/ˈbækəs nɔː fɔːm/ 巴科斯-诺尔范式 bā kē sī - nuò ěr fàn shì
production rule/prəˈdʌkʃn ruːl/ 产生式 chǎn shēng shì
terminal/ˈtɜːmɪnl/ 终结符 zhōng jié fú
non-terminal/nɒn ˈtɜːmɪnl/ 非终结符 fēi zhōng jié fú
syntax diagram/ˈsɪntæks ˈdaɪəɡræm/ 语法图 yǔ fǎ tú
16.2

逆波兰表示法(RPN)

在中缀(infix)记法中,运算符坐在它的操作数之间(3 + 4 * 2),需要括号和优先级规则。在逆波兰表示法(Reverse Polish Notation,RPN,后缀(postfix))中,运算符跟在它的操作数之后(3 4 2 * +),不需要括号。

把中缀转为逆波兰

用一个运算符栈(stack)。从左到右扫描:输出一个操作数;对一个运算符,先把任何更高或相等****优先级(precedence)的已入栈运算符弹到输出,然后把它压栈;把 ( 压栈;遇到 ) 弹出到输出直到匹配的 (。在最后,弹出所有运算符。例子:(3 + 4) * 2 → 3 4 + 2 *。

求值逆波兰

用一个操作数栈。从左到右扫描:把每个操作数压栈;遇到一个运算符,弹出顶上两个、应用它,并把结果压栈。求值 3 4 2 * +:

词法单元 栈
3 3
4 3, 4
2 3, 4, 2
* 3, 8
+ 11

结果:11。RPN 在求值时不需要括号并适合一个栈机器——这就是 JVM 和许多字节码(bytecode)解释器工作的方式。

"解释为什么用 RPN 求表达式的值"(两分)。 在 RPN 中运算符按它们被应用的顺序出现,所以表达式可以从左到右一趟求值,不需要括号,也不需要优先级规则;因此编译器或解释器处理起来更简单、更快。"指出一种合适的数据结构并说明理由":**栈,因为求值需要先用最近**压入的操作数(后进先出):每个操作数被压入,每个运算符弹出顶部两个,应用自身,再压入结果。被要求时要写出每个词法单元之后的栈内容。

手工把中缀转成 RPN。 (1) 按优先级规则给表达式完全加括号;(2) 把每个运算符移到它自己那对括号的右括号之后;(3) 去掉括号。于是 $(a - b) * (a + c) / 7$ 变成 $((a - b) * (a + c)) / 7$,再变成 a b - a c + * 7 /。注意 * 和 / 从左到右应用,所以除法是最后一个运算符,而不是乘法。更多转换:$((7 + 3) - (2 * 8)) / 6$ 是 7 3 + 2 8 * - 6 /;$(7 - 2 + 8) / (9 - 5)$ 是 7 2 - 8 + 9 5 - /;$a * b + b - d + 15$ 是 a b * b + d - 15 +;$(2 - 6) * (13 + 7) / 5$ 是 2 6 - 13 7 + * 5 /。

把 RPN 转回中缀。 用一个表达式栈处理 RPN:压入每个操作数;对每个运算符弹出两个,加括号写在它两侧,再压入结果。于是 a b / 4 * a b + - 是 $((a / b) * 4) - (a + b)$;5 2 + 9 3 - / 3 * 是 $((5 + 2) / (9 - 3)) * 3$;b a c - + d b + * c / 是 $((b + (a - c)) * (d + b)) / c$;a b - c + c a - * d / 是 $(((a - b) + c) * (c - a)) / d$。保留括号:去掉它们可能改变含义。

示例。 当$a = 17$、$b = 5$、$c = 7$、$d = 3$和$e = 10$时,计算a b - c d + * e /的值,并展示栈的状态。

词法单元 动作 栈(栈顶在右)
a 压入 17 17
b 压入 5 17, 5
- 弹出 5 和 17,压入 $17 - 5$ 12
c 压入 7 12, 7
d 压入 3 12, 7, 3
+ 弹出 3 和 7,压入 $7 + 3$ 12, 10
* 弹出 10 和 12,压入 $12 \times 10$ 120
e 压入 10 120, 10
/ 弹出 10 和 120,压入 $120 / 10$ 12

结果 12。对 - 和 / 弹出的顺序很重要:第二个弹出的值是左操作数,所以 a b - 是 $a - b$,不是 $b - a$。再来两个,方法相同:d a b + * c a - / 在 $a = 6, b = 12, c = 15, d = 5$ 时给出 $5 \times (6 + 12) / (15 - 6) = 90 / 9 = 10$;c a - b d + * b c + / 在 $a = 4, b = 12, c = 24, d = 6$ 时给出 $(24 - 4) \times (12 + 6) / (12 + 24) = 360 / 36 = 10$。

例题。 把 $(A + B) \times (C - D)$ 转换成逆波兰式,然后计算 $(3 + 4) \times (5 - 2)$。用一个运算符栈从左向右扫描。压入 (;输出 A;压入 +;输出 B;遇到 ) 时弹出直到匹配的 (,此时已输出 A B +。压入 ×,第二个括号同样处理,得到 C D -。最后弹出 ×。结果是:A B + C D - ×。要计算数值,则用一个操作数栈:压入 3,压入 4;+ 弹出两者并压入 7;压入 5,压入 2;- 弹出两者并压入 3;× 弹出 7 和 3 并压入 21。有两点能让这类题做得稳:转换过程中操作数保持原来的顺序(只有运算符在移动),而且每个运算符作用于栈中紧挨着它下面的两个值。

探索

运算符优先级——RPN 去掉了什么

在普通的中缀数学中,× 和 ÷ 比 + 和 − 结合得更紧,所以你必须以正确的顺序应用规则。逆波兰记法先写操作数(3 4 2 × + 1 −),固定顺序,所以不需要优先级规则。

词汇 训练
English 中文 拼音
infix/ˈɪnfɪks/ 中缀 zhōng zhuì
Reverse Polish Notation/rɪˈvɜːs ˈpəʊlɪʃ nəʊˈteɪʃn/ 逆波兰表示法 nì bō lán biǎo shì fǎ
postfix/ˈpəʊstfɪks/ 后缀 hòu zhuì
stack/stæk/ 栈 zhàn
precedence/ˈpresɪdəns/ 优先级 yōu xiān jí
bytecode/ˈbaɪtkəʊd/ 字节码 zì jié mǎ
16.2

考官认可的定义

定义题按固定的表述给分。把这些记准确,并且只写一个答案。

术语 定义
多任务 几个进程同时保存在内存中,处理器在它们之间切换,使它们看起来在同时运行
进程 已装入内存并正在执行(或准备执行)的程序
运行 / 就绪 / 阻塞 占有处理器 / 等待处理器 / 在 I/O 完成等事件发生之前不能继续
调度 决定哪个就绪进程接下来得到处理器,以及得到多久
抢占式调度 正在运行的进程可以被中断并移到就绪,让另一个进程运行
虚拟内存 用辅助存储器扩展 RAM,只把当前需要的页保存在物理内存中
分页 把内存和程序分成固定大小的页,按需要在磁盘和 RAM 之间移动
分段 把程序分成大小可变的逻辑段,每段由段表映射到内存
磁盘抖动 页在 RAM 和磁盘之间交换得如此频繁,以至于几乎没有有用的处理
解释器 一次一条语句地翻译并执行程序,不产生翻译版本
编译器 在运行之前把整个高级语言程序翻译成机器(目标)代码
词法分析 把源代码转换成词法单元,去掉空白和注释,并建立符号表
语法分析 检查词法单元是否符合语言的文法并构建解析树
巴科斯-诺尔范式 一种用于描述语言语法的记号:由终结符和非终结符构成的<name> ::= alternatives形式规则
逆波兰表示法 把每个运算符写在其操作数之后的表达式写法,使表达式能用栈、不用括号求值
16.2

考试技巧

  • OS 题按点名的机制评分:调度、内存管理、I/O 缓冲和假脱机、文件管理;对界面,文件名而非地址、点击而非命令、驱动程序、GUI。
  • 进程状态及其转移和每种转移的原因;调度例程按功能加优点加缺点;内核保存状态、识别中断、处理、恢复。
  • 虚拟内存:磁盘扩展 RAM、页交换、地址翻译;分页是固定大小且不可见,分段是可变大小且逻辑的;抖动是交换而不是工作。
  • 解释器:一次一条语句,先翻译再执行,不存储任何东西。编译阶段:词法单元和符号表、文法和解析树、代码、优化。
  • BNF:每张图一条规则,| 表示选择,递归表示重复,终结符不加括号而非终结符加尖括号。要说出字符串违反了哪条规则。
  • RPN:运算符在操作数之后,用栈求值,写出每一步;转换时完全加括号;转回时保留括号。

常见错误

  • 把多任务描述成"同时运行几个程序"而不说处理器在它们之间切换。
  • 让阻塞的进程直接进入运行,或把"时间片用完"当作运行到阻塞的原因。
  • 混淆最短作业优先(非抢占)与最短剩余时间(抢占),或混淆轮转与优先级。
  • 把虚拟内存定义为"把硬盘当 RAM 用"而不提页的交换。
  • 说解释器"把程序转换成机器码然后运行";那是编译器。
  • 把语法检查放进词法分析,或在配对题中把优化放在代码生成之前。
  • 把 BNF 的重复写成 <letter>* 或用省略号;要用递归。非终结符漏掉尖括号。
  • 求 RPN 值时把 - 或 / 的操作数弄反,或把 $a * b + c$ 的 RPN 写成 a b c + *。

该知识点的互动课程

逐步完成,配合即时检查练习。

历年真题

更多 A-Level 计算机科学 知识点

登录或创建账户

IGCSE, A-Level & AP