CSP-S 2022 提高级 第一轮试题(初赛)答案及解析
一、单项选择题
- 在 Linux 系统终端中,用于切换工作目录的命令为( )。
A. ls
B. cd
C. cp
D. all
答: B
ls的作用是列出当前目录中的所有文件
cd是切换目录
cp是复制文件
Linux中没有all命令
- 你同时用 time 命令和秒表为某个程序在单核 CPU 的运行计时。假如 time 命令的输出如下:
real 0m30.721s
user 0m24.579s
sys 0m6.123s
以下最接近秒表计时的时长为( )。
A. 30s
B. 24s
C. 18s
D. 6s
答:A
real: 总的运行时间,从命令开始执行到结束的时间,包括等待CPU时间和其他进程时间。
user: 用户CPU时间,即在用户态下花费的时间,不包括用于内核操作的时间。
sys: 系统CPU时间,即在内核态下花费的时间,比如执行系统调用所花费的时间。
秒表计时的时长接近于程序运行的总时间,即real后面显示的时间。
扩展阅读:以下材料引用自https://www.cnblogs.com/jluzhsai/p/4870595.html
进程时间也称CPU时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴嗒计算,通常使用三个进程时间值,即实际时间(Real)、用户CPU时间(User)和系统CPU时间(Sys)。
实际时间指实际流逝的时间;用户时间和系统时间指特定进程使用的CPU时间。具体区别如下:
Real是从进程开始执行到完成所经历的挂钟(wall clock)时间,包括其他进程使用的时间片(time slice)和本进程耗费在阻塞(如等待I/O操作完成)上的时间。该时间对应秒表(stopwatch)直接测量。
User是进程执行用户态代码(内核外)耗费的CPU时间,仅统计该进程执行时实际使用的CPU时间,而不计入其他进程使用的时间片和本进程阻塞的时间。
Sys是该进程在内核态运行所耗费的CPU时间,即内核执行系统调用所使用的CPU时间。
CPU总时间(User+Sys)是CPU执行用户进程操作和内核(代表用户进程执行)系统调用所耗时间的总和,即该进程(包括其线程和子进程)所使用的实际CPU时间。若程序循环遍历数组,则增加用户CPU时间;若程序执行exec或fork等系统调用,则增加系统CPU时间。
在多核处理器机器上,若进程含有多个线程或通过fork调用创建子进程,则实际时间可能小于CPU总时间——因为不同线程或进程可并行执行,但其时间会计入主进程的CPU总时间。若程序在某段时间处于等待状态而并未执行,则实际时间可能大于CPU总时间。其数值关系总结如下:
Real < CPU,表明进程为计算密集型(CPU bound),利用多核处理器的并行执行优势;
Real ≈ CPU,表明进程为计算密集型(CPU bound),未并行执行;
Real > CPU,表明进程为I/O密集型(I/O bound),多核并行执行优势并不明显。
在单核处理器上,Real时间和CPU时间之差,即Real- (User + Sys)是所有延迟程序执行的因素的总和。可估算程序运行期间的CPU利用率为CpuUsage = (User + Sys)/ Real * 100(%)。
在SMP(对称多处理系统)上,该差值近似为Real* ProcessorNum - (User + Sys)。这些因素包括:
调入程序文本和数据的I/O操作;
获取程序实际使用内存的I/O操作;
由其它程序消耗的CPU用时;
由操作系统消耗的CPU用时。
- 若元素 a、b、c、d、e、f 依次进栈,允许进栈、退栈操作交替进行,但不允许连续三次退栈操作,则不可能得到的出栈序列是( )。
A. dcebfa
B. cbdaef
C. bcaefd
D. afedcb
答:D
该类问题的解题策略为:如果x出栈,那么在x前入栈的元素除了已经出栈的元素,都在栈内。
A 选项dcebfa成立:
已出栈序列 | 栈内:栈底…栈顶 | 下一步操作 |
---|---|---|
d | a b c | 出栈c |
d c | a b | 入栈e,出栈e |
d c e | a b | 出栈b |
d c e b | a | 入栈f 出栈f |
d c e b f | a | 出栈a |
d c e b f a |
B选项cbdaef成立:
已出栈序列 | 栈内:栈底…栈顶 | 下一步操作 |
---|---|---|
c | a b | 出栈b |
c b | a | 入栈d,出栈d |
c b d | a | 出栈a |
c b d a | 空 | 入栈e 出栈e |
c b d a e | 空 | 入栈f 出栈f |
c b d a e f | 空 |
C选项bcaefd成立:
已出栈序列 | 栈内:栈底…栈顶 | 下一步操作 |
---|---|---|
b | a | 入栈c,出栈c |
b c | a | 出栈a |
b c a | 空 | 入栈d |
b c a | d | 入栈e 出栈e |
b c a e | d | 入栈f 出栈f |
b c a e f | d | 出栈 d |
b c a e f d |
D选项afedcb不成立:
已出栈序列 | 栈内:栈底…栈顶 | 下一步操作 |
---|---|---|
空 | 入栈a,出栈a | |
a | 空 | 入栈b c d e f |
a | b c d e f | 出栈 f e d c b |
a f e d c b | 空 |
需要连续5次出栈,才能得到目标序列,不满足“不能有连续3次出栈”,因此D选项不成立。
4.考虑对 n 个数进行排序,以下最坏时间复杂度低于
O
(
n
2
)
O(n^2)
O(n2) 的排序方法是( )。
A. 插入排序
B. 冒泡排序
C. 归并排序
D. 快速排序
答:C
插入、冒泡的平均和最坏时间复杂度都是 O ( n 2 ) O(n^2) O(n2)
快速排序的平均时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),退化后最坏时间复杂度是 O ( n 2 ) O(n^2) O(n2)
归并排序的平均和最坏时间复杂度都是 O ( n l o g n ) O(nlogn) O(nlogn)
- 计算机系统用小端(Little Endian)和大端(Big Endian)来描述多字节数据的存储地址顺序模式,其中小端表示将低位字节数据存储在低地址的模式、大端表示将高位字节数据存储在低地址的模式。在小端模式的系统和大端模式的系统分别编译和运行以下 C++代码段表示的程序,将分别输出什么结果?( )
unsigned x = 0xDEADBEEF;
unsigned char *p = (unsigned char *)&x;
printf(“%X”, *p);
A. EF、EF
B. EF、DE
C. DE、EF
D. DE、DE
答:B
unsigned是4字节32位类型,unsigned char是1字节8位的类型。
把unsigned char类型的指针p设为unsigned类型变量x的地址,*p即为x变量的低8位数据。
如果小端模式,低位字节存储在低地址,0xDEADBEEF最低位一字节保存的数据是EF。
如果大端模式,高位字节存储在低地址,0xDEADBEEF最高位一字节保存的数据是DE。
注意,字节内部数据的先后顺序不会发生改变。
- 一个深度为 5(根结点深度为 1)的完全 3 叉树,按前序遍历的顺序给结点从 1 开始编号,则第 100 号结点的父结点是第( )号。
A. 95
B. 96
C. 97
D. 98
答:C
树一共5层,每层结点数分别为1,3,9,27,81。
1层满三叉树共1个结点
2层满三叉树共4个结点
3层满三叉树共13个结点
4层满三叉树共40个结点
按照前序遍历顺序先遍历结点1的第一个子树,该子树是4层满三叉树,共40个结点。遍历第二个子树,也是4层满三叉树,共40个结点,因此1的第三个孩子的编号为82。
结点82的第一个子树为3层满三叉树,共13个结点。
82的第二个孩子编号为96。96的第一个孩子编号为97。97是第5层的结点,97的三个孩子编号分别为98,99,100。
因此100的父结点编号是97。
以下图中x node:y,意思是子树根结点编号是x,该子树共有y个结点。单独一个数字就是结点编号。
- 强连通图的性质不包括( ):
A. 每个顶点的度数至少为 1
B. 任意两个顶点之间都有边相连
C. 任意两个顶点之间都有路径相连
D. 每个顶点至少都连有一条边
答:B
强连通图中任意两个顶点A、B之间,从A到B与从B到A都有路径。
A. 如果一个顶点度为0,则该顶点与其它顶点不连通,不符合强连通图的定义。因此每个顶点度数至少为1。正确。
B. 是错误的,两顶点之间有双向的路径即可,不要求一定有边相连。
C. 根据强连通图的定义,是正确的。
D. 每个顶点至少连一条边,就是度至少为1。和A选项的表述等价,是正确的。
- 每个顶点度数均为 2 的无向图称为“2 正规图”。由编号为从1到n的顶点构成的所有2 正规图,其中包含欧拉回路的不同 2 正规图的数量为( )。
A. n!
B. (n-1)!
C. n!/2
D. (n-1)!/2
答:D
一个图是欧拉图(包含欧拉回路)的条件是充分必要条件是每个顶点的度都是偶数度。
因此根据题目的定义,2正规图每个顶点度数都为2,那么该图一定是欧拉图,其中包含欧拉回路。
每个顶点度都为2,设共有n个顶点,总度数为2,每条边提供2个度,因此有n条边。也就是n个顶点n条边连成一个环
顶点1连出的一条边连到的顶点有n-1种选择
假设连到顶点2,第2步顶点2连到的顶点除了顶点1,有n-2种选择;
假设连到顶点3,第3步顶点3连到的顶点除了顶点1,2,有n-3种选择;
……
第n-1步,顶点n-1只能连到顶点n,有1种选择。
顶点n再连接到顶点1,形成环。
共有 ( n − 1 ) ( n − 2 ) . . . 1 = ( n − 1 ) ! (n-1)(n-2)...1=(n-1)! (n−1)(n−2)...1=(n−1)!种情况
而这样的环也可以是从顶点1连到顶点n,顶点n连到顶点n-1,顶点n-1连到顶点n-2,……,连到顶点2,顶点2连到顶点1得到。因此相同的环是算了两遍的,因此应该再除以2。结果是 ( n − 1 ) ! / 2 (n-1)!/2 (n−1)!/2
- 共有 8 人选修了程序设计课程,期末大作业要求由 2 人组成的团队完成。假设不区分每个团队内 2 人的角色和作用,请问共有多少种可能的组队方案。( )。
A. 28
B. 32
C. 56
D. 64
答:A
题目问的是组队的方案,并不没有要求组成4队。8人中选出2人组队,选出的2人不区分角色作用,也就是选出的2人没有顺序,是组合。因此该问题就是求8个不同元素中选出2个元素的组合数,为C(8,2)=28
- 小明希望选到形如“省 A·LLDDD ”的车牌号。车牌号在“·”之前的内容固定的 5 位号码中,前 2 位必须是大写英文字母,后 3 位必须是阿拉伯数字(L代表 A 至 Z,D 表示 0 至 9,两个 L 和三个 D 之间可能相同也可能不同)。请问总共有多少个可供选择的车牌号。( )
A. 20280
B. 52000
C. 676000
D. 1757600
答:C
第1步确定第1个“L"位置的字母,有26种情况。
第2步确定第2个“L"位置的字母,有26种情况。
第3步确定第1个“D"位置的数字,有10种情况。
第4步确定第2个“D"位置的数字,有10种情况。
第5步确定第3个“D"位置的数字,有10种情况。
根据乘法原理,总情况数为
26
∗
26
∗
10
∗
10
∗
10
=
676000
26*26*10*10*10=676000
26∗26∗10∗10∗10=676000
- 给定地址区间为 0~9 的哈希表,哈希函数为 h(x) = x % 10,采用线性探查的冲突解决策略(对于出现冲突情况,会往后探查第一个空的地址存储;若地址 9 冲突了则从地址 0 重新开始探查)。哈希表初始为空表,依次存储(71, 23, 73, 99, 44, 79, 89)后,请问 89 存储在哈希表哪个地址中。( )
A. 9
B. 0
C. 1
D. 2
答:
数值x,x%10的结果为h(x),将该数值尝试放到下标为h(x)的位置,如果该位置已经有数字,就向后找到第一个空位(下标0的下一个位置是下标0),将数字存储进去。
数组下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
存储71 | 71 | |||||||||
存储23 | 71 | 23 | ||||||||
存储73 | 71 | 23 | 73 | |||||||
存储99 | 71 | 23 | 73 | 99 | ||||||
存储44 | 71 | 23 | 73 | 44 | 99 | |||||
存储79 | 79 | 71 | 23 | 73 | 44 | 99 | ||||
存储89 | 79 | 71 | 89 | 23 | 73 | 44 | 99 |
89存储在下标2的位置
- 对于给定的 n,分析以下代码段对应的时间复杂度,其中最为准确的时间复杂度为( )。
int i, j, k = 0;
for (i = 0; i < n; i++) {
for (j = 1; j < n; j*=2) {
k = k + n / 2;
}
}
A.
O
(
n
)
O(n)
O(n)
B.
O
(
n
log
n
)
O(n \log n)
O(nlogn)
C.
O
(
n
n
)
O(n\sqrt{n})
O(nn)
D.
O
(
n
2
)
O(n^2)
O(n2)
答:B
i从0~n-1循环,循环n次
j从1到n-1,j每次乘以2,j每次循环乘以2直至达到n,循环的次数为 log 2 n \log_2{n} log2n,
每层循环的循环次数相乘,是总的循环次数。
整体时间复杂度是 O ( n log n ) O(n\log n) O(nlogn)
- 以比较为基本运算,在 n 个数的数组中找最大的数,在最坏情况下至少要做( )次运算。
A. n/2
B. n-1
C. n
D. n+1
答:B
求最大值,设一个变量(如变量maximum)表示最大值,将其初值设为第一个数。而后循环n-1次,将第2到第n个数分别和maximum变量比较,如果该数字比maximum变量大,就把maximum的值设为该数字。因此需要比较n-1次。不存在比较次数更少的算法。
- ack 函数在输入参数“(2,2)”时的返回值为()。
unsigned ack(unsigned m, unsigned n) {
if (m == 0) return n + 1;
if (n == 0) return ack(m - 1, 1);
return ack(m - 1, ack(m, n - 1));
}
A. 5
B. 7
C. 9
D. 13
答:B
阿克曼函数,对于这样的递归函数求值,一个常见的方法是递归转递推。设二维数组a,a[i][j]
表示ack(i,j)
。从a的第0行、第0列开始,依次推导,直到推出a[2][2]
对于a[m][n]
,m为0时,返回n+1。因此a[0][0]=1
,a[0][1]=2
,a[0][2]=3, a[0][3]=4, a[0][4]=5
对于a[m][n]
,n为0时,返回a[m-1][1]
。a[1][0]=a[0][1]=2
其它情况a[m][n]=a[m-1][a[m][n-1]]
a[1][1]=a[0][a[1][0]]=a[0][2]=3
a[1][2]=a[0][a[1][1]]=a[0][3]=4
a[1][3]=a[0][a[1][2]]=a[0][4]=5
a[1][4]=a[0][a[1][3]]=a[0][5]=6
a[1][5]=a[0][a[1][4]]=a[0][6]=7
a[2][0]=a[1][1]=3
a[2][1]=a[1][a[2][0]]=a[1][3]=5
a[2][2]=a[1][a[2][1]]=a[1][5]=7
实际在纸上算时最好使用填表法,以下表格第m行第n列的值为a[m][n]
m\n | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 | |
2 | 3 | 5 | 7 |