讲解视频推荐:
【BOK408真题讲解-2023】
一、数据结构
1. 算法题(图的邻接矩阵)13’
已知有向图 G 采用邻接矩阵存储,类型定义如下:
typedef struct{ //图的类型定义int num Vertices, numEdges; //图的顶点数和有向边数char VerticesList[MAXY]; //顶点表,MAXY 为己定义常量int Edge[MAXY][MAXY]; //邻接矩阵
} MGraph;
将图中出度大于入度的顶点称为 K 顶点。例如在下图中, 顶点 a 和 b 为 K 顶点。
请设计算法:int printVertices(MGraph G) ,对给定的任意非空有向图 G , 输出 G 中所有的 K 顶点, 并返回 K 顶点的个数。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想, 采用 C 或 C++ 语言描述算法,关键之处给出注释。
【解析】:
(1)采用邻接矩阵表示有向图时,一行中 1 的个数为该行对应顶点的出度,一列中 1 的个数为该列对应顶点的入度。使用一个初值为零的计数器记录 K 顶点数。对图 G 的每个顶点,根据邻接矩阵计算其出度 outdegree 和入度 indegree 。若 outdegree > indegree ,则输出该顶点且计数器 + 1 ,最后返回计数器的值。
(2)用 C 语言描述的算法:
int printVertices(MGraph G){ //采用邻接矩阵存储,输出 K 顶点,返回个数int outdegree, indegree, k, m, count = 0;for(k = 0; k < G.Vertices; k++){outdegree = indegree = 0;for(m = 0; m < G.Vertices; m++){outdegree += G.Edge[k][m];} //计算出度for(m = 0; m < G.Vertices; m++){indegree += G.Edge[m][k];} //计算入度if(outdegree > indegree){printf("%c", G.VerticesList[k]);count++;}}return count; //返回 K 顶点个数
}
图的四种存储方式(邻接矩阵、邻接表、十字链表、邻接多重表)
2. 置换-选择排序(生成初始归并段)10’
对含有 n ( n > 0 ) 个记录的文件进行外部排序,采用置换-选择排序生成初始归并段时需要使用一个工作区, 工作区中能保存 m 个记录。请回答下列问题。
(1)若文件中含有 19 个记录, 其关键字依次是 51, 94, 37, 92, 14, 63, 15, 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100, 则当 m = 4 时,可生成几个初始归并段?各是什么?
(2)对任意的 m ( n >> m > 0 ) , 生成的第一个初始归并段的长度最大值和最小值分别是多少?
【解析】:
(1)当 m = 4 时,可生成 3 个初始归并段,分别为 {37, 51, 63, 92, 94, 99} ,{14, 15, 23, 31, 48, 56, 60, 90, 166} ,{8, 17, 43, 100} 。
排序过程如下表所示:
输出文件 FO | 工作区 WA | 输入文件 FI |
---|---|---|
—— | —— | 51, 94, 37, 92, 14, 63, 15, 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
—— | 51, 94, 37, 92 | 14, 63, 15, 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37 | 51, 94, 14, 92 | 63, 15, 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51 | 63, 94, 14, 92 | 15, 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51, 63 | 15, 94, 14, 92 | 99, 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51, 63, 92 | 15, 94, 14, 99 | 48, 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51, 63, 92, 94 | 15, 48, 14, 99 | 56, 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51, 63, 92, 94, 99 | 15, 48, 14, 56 | 23, 60, 31, 17, 43, 8, 90, 166, 100 |
37, 51, 63, 92, 94, 99# | 15, 48, 14, 56 | 23, 60, 31, 17, 43, 8, 90, 166, 100 |
14 | 15, 48, 23, 56 | 60, 31, 17, 43, 8, 90, 166, 100 |
14, 15 | 60, 48, 23, 56 | 31, 17, 43, 8, 90, 166, 100 |
14, 15, 23 | 60, 48, 31, 56 | 17, 43, 8, 90, 166, 100 |
14, 15, 23, 31 | 60, 48, 17, 56 | 43, 8, 90, 166, 100 |
14, 15, 23, 31, 48 | 60, 43, 17, 56 | 8, 90, 166, 100 |
14, 15, 23, 31, 48, 56 | 60, 43, 17, 8 | 90, 166, 100 |
14, 15, 23, 31, 48, 56, 60 | 90, 43, 17, 8 | 166, 100 |
14, 15, 23, 31, 48, 56, 60, 90 | 166, 43, 17, 8 | 100 |
14, 15, 23, 31, 48, 56, 60, 90, 166 | 100, 43, 17, 8 | —— |
14, 15, 23, 31, 48, 56, 60, 90, 166# | 100, 43, 17, 8 | —— |
8 | 100, 43, 17 | —— |
8, 17 | 100, 43 | —— |
8, 17, 43 | 100 | —— |
8, 17, 43, 100 | —— | —— |
8, 17, 43, 100# | —— | —— |
(2)对任意的 m ,生成的第一个初始归并段的长度最大值为 n ,最小值为 m 。
外部排序(败者树、置换-选择排序、最佳归并树)
二、计算机组成原理
1. 虚拟存储器 14’
已知计算机 M 字长为 32 位,按字节编址,采用请求调页策略的虚拟存储管理方式,虚拟地址为 32 位, 页大小为 4KB ; 数据 Cache 采用 4 路组相联映射方式, 数据区大小为 8KB ,主存块大小为 32B 。现有 C 语言程序段如下:
int a[24][64];
…
for (i = 0; i < 24; i++){for (j = 0; j < 64; j++) {a[i][j] = 10;}
}
已知二维数组 a 按行优先存放,在虚拟地址空间中分配的起始地址为 0042 2000H , sizeof(int) = 4 ,假定在 M 上执行上述程序段之前数组 a 不在主存, 且在该程序段执行过程中不会发生页面置换。请回答下列问题。
(1)数组 a 分布在几个页面中?对于数组 a 的访问, 会发生几次缺页异常?页故障地址各是什么?
(2)不考虑变量 i 和 j ,该程序段的数据访问是否具有时间局部性?为什么?
(3)计算机 M 的虚拟地址(A31 ~ A0)中哪几位用作块内地址? 哪几位用作 Cache 组号?a[1][0] 的虚拟地址是多少?其所在主存块对应的 Cache 组号是多少?
(4)数组 a 占用多少主存块?假设上述程序段执行过程中数组 a 的访问不会和其他数据发生 Cache 访问冲突, 则数组 a 的 Cache 命中率是多少? 若将循环中 i 和 j 的次序按如下方式调换:
for (j = 0; j < 64; j++){for (i = 0; i < 24; i++) {a[i][j] = 10;}
}
则数组 a 的 Cache 命中率又是多少?
【解析】:
(1)
-
数组 a 有 24 × 64 × 4B = 6KB ,由于页大小为 4KB,因此数组 a 分布在 2 个相邻的页面中。
-
由于数组 a 不在主存,因此会发生 2 次缺页异常。页故障地址为 0042 2000H 和 0042 3000H 。
(2)该程序段的数据访问没有时间局部性,因为每个数组元素仅被访问 1 次。
(3)
-
主存块大小为 32B = 25B ,故计算机 M 的虚拟地址中 A4 ~ A0(5 位)用作块内地址。
-
数据区大小为 8KB ,故 Cache 数据区共有 8KB / 32B = 28 = 256 行;
数据 Cache 采用 4 路组相联映射方式,故 Cache 数据区共有 28 / 4 = 26 = 64 组;
故计算机 M 的虚拟地址中 A10 ~ A5(6 位)用作 Cache 组号。 -
虚拟地址空间的起始地址为 0042 2000H ,得到 a[1][0] 的虚拟地址是 0042 2000H + 1 × 64 × 4 + 0 × 4 = 0042 2100H 。其所在主存块对应的 Cache 组号是 0042 2100H(A10 ~ A5)= 001000 = 8 。
假设主存地址为 32 位,则有
tag(21 位) | Cache 组号(6 位) | 块内地址(5 位) |
---|
(4)
-
数组 a 占用 6KB / 32B = 192 个主存块。
-
主存块大小为 32B ,每个主存块可以存放 8 个元数组素,当循环中 i 和 j 的次序不调换时,数组 a 的 Cache 命中率是 7 / 8 = 87.5% 。
-
数组 a 占用 192 个主存块,Cache 数据区共有 64 组,因此每个 Cache 组中只有 192 / 64 = 3 个 Cache 行存放数组 a 中的数据,而每个 Cache 组有 4 行,因此不会发生替换。当循环中 i 和 j 的次序调换时,数组 a 的 Cache 命中率是 7 / 8 = 87.5% 。
虚拟内存管理
2. 程序的机器级代码表示 9’
上题中的 C 程序段在计算机 M 上的部分机器级代码如下, 每个机器级代码行中依次包含指令序号、虚拟地址、机器指令和汇编指令。
请回答下列问题。
(1)第 20 条指令的虚拟地址是多少?
(2)已知第 2 条 jmp 和第 7 条 jge 都是跳转指令, 其操作码分别是 EBH 和 7DH ,跳转目标地址分别为 0040 1084H 、0040 10BCH ,这两条指令都采用什么寻址方式?给出第 2 条指令 jmp 的跳转目标地址计算过程。
(3)已知第 19 条 mov 指令的功能为 “a[i][j] ← 10” ,其中 ecx 和 edx 为寄存器名,0042 2000H是数组 a 的首地址, 指令中源操作数采用什么寻址方式?已知 edx 中存放的是变量 j,ecx 中存放的是什么?根据该指令的机器码判断计算机 M 采用的是大端还是小端方式。
(4)第一次执行第 19 条指令时, 取指令过程中是否会发生缺页异常?为什么?
【解析】:
(1)由于第 19 条指令的虚拟地址是 0040 10AE ,且第 19 条指令占 11 个字节,因此第 20 条指令的虚拟地址是 0040 10B9H 。
(2)这两条指令都采用相对寻址方式。
-
第 2 条指令 jmp 的跳转目标地址计算过程:PC + “1” + “偏移量” = 0040 1079H + 2H + 09H = 0040 1084H ;
-
第 7 条指令 jge 的跳转目标地址计算过程:PC + “1” + “偏移量” = 0040 1088H + 2H + 32H = 0040 10BCH 。
(3)
-
指令中源操作数采用立即数寻址方式。
-
ecx 中存放的是 i × 64 × 4 = i × 256 。
-
计算机 M 采用的是小端方式。
(4)第一次执行第 19 条指令时, 取指令过程中不会发生缺页异常。因为页面大小为 4KB = 212B ,因此虚拟地址高 20 位代表虚页号,低 12 位代表页内地址。由于上述指令的虚页号均为 00401H ,得出以上所有指令都在同一页面上,所以执行第 19 条指令时,必然不会发生缺页。
指令系统 II
三、操作系统
1. 同步与互斥 7’
现要求学生使用 swap 指令和布尔型变量 lock 实现临界区互斥。lock 为线程间共享的变量,lock 的值为 TRUE 时线程不能进入临界区,为 FALSE 时线程能够进入临界区。某同学编写的实现临界区互斥的伪代码如下图 (a) 所示。
请回答下列问题。
(1)上图 (a) 的伪代码中哪些语句存在错误?将其改为正确的语句(不增加语句的条数) 。
(2)上图 (b) 给出了交换两个变量值的函数 newSwap() 的代码,是否可以用函数调用语句 “newSwap(&key, &lock)” 代替指令 “swap key, lock” 以实现临界区互斥?为什么?
【解析】:
(1)① 将 if(key == TRUE) 改为 while(key == TRUE) ;② 将 lock = TRUE 改为 lock = FALSE 。
由题意可知 lock 是全局变量,key 是局部变量。当线程 1 运行这段代码时,key1 = TRUE ,交换后,key1 = FALSE 、lock = TRUE ,然后线程 1 进入临界区;与此同时,若线程 2 开始运行这段代码,key2 = TRUE ,交换后,key2 = FALSE 、lock = TRUE ,然后线程 2 进入临界区,无法达到互斥的要求。
(2)不可以,函数调用语句 “newSwap(&key, &lock)” 不具备原子性,可能会导致多个并发执行的进程同时进入临界区。
进程与线程 III(同步与互斥)
2. I/O 管理概述 8’
进程 P 通过执行系统调用从键盘接收一个字符的输入,已知此过程中与进程 P 相关的操作包括: ① 将进程 P 插入就绪队列;② 将进程 P 插入阻塞队列;③ 将字符从键盘控制器读入系统缓冲区;④ 启动键盘中断处理程序;⑤ 进程 P 从系统调用返回;⑥ 用户在键盘上输入字符。以上编号 ① ~ ⑥ 仅用于标记操作,与操作的先后顺序无关。请回答下列问题。
(1)按照正确的操作顺序,操作 ① 的前一个和后一个操作分别是上述操作中的哪一个?操作 ⑥ 的后一个操作是上述操作中的哪一个?
(2)在上述哪个操作之后 CPU 一定从进程 P 切换到其他进程?在上述哪个操作之后 CPU 调度程序才能选中进程 P 执行?
(3)完成上述哪个操作的代码属于键盘驱动程序?
(4)键盘中断处理程序执行时,进程 P 处于什么状态? CPU 处于内核态还是用户态?
【解析】:
(1)正确的操作顺序为 ② → ⑥ → ④ → ③ → ① → ⑤ ,即 将进程 P 插入阻塞队列 → 用户在键盘上输入字符 → 启动键盘中断处理程序 → 将字符从键盘控制器读入系统缓冲区 → 将进程 P 插入就绪队列 → 进程 P 从系统调用返回。
操作 ① 的前一个操作是 ③ ,后一个操作是 ⑤ ,操作 ⑥ 的后一个操作是 ④ 。
(2)在操作 ②(将进程 P 插入阻塞队列)之后 CPU 一定从进程 P 切换到其他进程;在操作 ①(将进程 P 插入就绪队列)之后 CPU 调度程序才能选中进程 P 执行。
(3)上述操作 ③ 的代码属于键盘驱动程序。
(4)键盘中断处理程序执行时,进程 P 处于阻塞态,CPU 处于内核态。
输入/输出管理 I(概述)
四、计算机网络
文件传输协议(FTP)9’
某网络拓扑如下图所示,主机 H 登录 FTP 服务器后,向服务器上传一个大小为 18000B 的文件 F 。假设 H 为传输 F 建立数据连接时,选择的初始序号为 100 ,MSS = 1000B ,拥塞控制初始阈值为 4MSS,RTT = 10ms ,忽略 TCP 段的传输时延; 在 F 的传输过程中,H 均以 MSS 段向服务器发送数据,且未发生差错、丢包和乱序现象。
请回答下列问题。
(1)FTP 的控制连接是持久的还是非持久的? FTP 的数据连接是持久的还是非持久的? H 登录 FTP 服务器时, 建立的 TCP 连接是控制连接还是数据连接?
(2)H 通过数据连接发送 F 时,F 的第 1 个字节的序号是多少?在断开数据连接过程中, FTP 服务器发送的第二次挥手 ACK 段的确认序号是多少?
(3)H 通过数据连接发送 F 的过程中,当 H 收到确认序号为 2101 的确认段时,H 的拥塞窗口调整为多少?收到确认序号为 7101 的确认段时,H 的拥塞窗口调整为多少?
(4)H 从请求建立数据连接开始,到确认 F 已被服务器全部接收为止, 至少需要多长时间? 期间应用层数据平均发送速率是多少?
【解析】:
(1)FTP 的控制连接是持久的;FTP 的数据连接是非持久的;H 登录 FTP 服务器时, 建立的 TCP 连接是控制连接。
在 FTP 会话期间,控制连接一直处于保持状态,是持久的。每次需要传输文件时,FTP 客户机和服务器之间会建立一个临时的数据连接,用于传输文件数据,是非持久的。控制连接用于传输命令和控制信息,登陆操作涉及身份验证、发送命令等控制信息,因此使用控制连接。
(2)H 通过数据连接发送 F 时,F 的第 1 个字节的序号是 101 ,在断开数据连接过程中, FTP 服务器发送的第二次挥手 ACK 段的确认序号是 18102 。
建立连接时,FTP 客户机发送的第一次握手 SYN 段要消耗一个序号,选择的初始序号为 100 ,因此发送文件 F 时,第 1 个字节的序号是 101 ,文件 F 共有 18000 字节,需占用 18000 个序号,释放连接时,FTP 客户机发送的第一次挥手 FIN 段也要消耗一个序号,故该 FIN 段的序号为 18101 ,因此 TCP 服务器发送的第二次挥手 ACK 段的确认序号是 18102 。
(3)H 通过数据连接发送 F 的过程中,当 H 收到确认序号为 2101 的确认段时,H 的拥塞窗口调整为 3MSS ;收到确认序号为 7101 的确认段时,H 的拥塞窗口调整为 5MSS 。
拥塞控制初始阈值为 4MSS :
N 个传输轮次后 | 初始时 | N = 1 | N = 2 | N = 3 |
---|---|---|---|---|
拥塞窗口大小 | 1MSS | 2MSS | 4MSS | 5MSS |
-
第 1 轮时,当 H 收到确认序号为 1101 的确认段时,H 的拥塞窗口从 1MSS 调整为 2MSS 。
-
第 2 轮时,当 H 收到确认序号为 2101 的确认段时,H 的拥塞窗口从 2MSS 调整为 3MSS ;当 H 收到确认序号为 3101 的确认段时,H 的拥塞窗口从 3MSS 调整为 4MSS 。
-
第 3 轮时,当 H 收到确认序号为 4101、5101、6101、7101 的确认段后,H 的拥塞窗口从 4MSS 调整为 5MSS 。
(4)H 从请求建立数据连接开始,到确认 F 已被服务器全部接收为止, 至少需要 6 × RTT = 60ms ;期间应用层数据平均发送速率是 18000B × 8 / 60ms = 2.4Mbps 。
文件 F 大小 18000B = 18MSS ,则发送完 F 需要 5 个 RTT ,此外还需要 1 个额外的 RTT 用来建立 TCP 连接。
k | k = 1 | k = 2 | k = 3 | k = 4 | k = 5 |
---|---|---|---|---|---|
第 k 轮最大数据传输量 | 1MSS | 2MSS | 4MSS | 5MSS | 6MSS |
应用层 II(文件传输协议FTP)【★★】