GESP 客观题评测系统

2023-09-Level-5

2023-09-Level-5

试卷解析总览,可直接查看每题答案与解析。

单选题(每题 2 分)

1 题(单选题

近年来,线上授课变得普遍,很多有助于改善教学效果的设备也逐渐流行,其中包括比较常用的手写板,那么它属于哪类设备?()。

A.
输入
B.
输出
C.
控制
D.
记录

正确答案A

解析详情

【答案】A

【考点】计算机输入设备

【解析】 手写板用于捕捉手写笔迹并将其转化为数字信号输入计算机,属于典型的输入设备。

【易错点】 容易将输入设备与输出设备(如显示器)混淆。

2 题(单选题

如果 a 和 b 均为 int 类型的变量,且 b 的值不为 0,那么下列能正确判断“a 是 b 的3倍”的表达式是()。

A.
(a >> 3 == b)
B.
(a - b) % 3 == 0
C.
(a / b == 3)
D.
(a == 3 * b)

正确答案D

解析详情

【答案】D

【考点】算术运算与逻辑判断

【解析】 判断 a 是 b 的 3 倍即验证 a = 3b 是否成立,C++ 中对应的逻辑表达式为 a == 3 * b。选项 C 的 a / b == 3 在整数除法下不严谨,如 a=11, b=3 时结果也为真。

【易错点】 误选 C,忽略了整数除法向下取整的特性。

3 题(单选题

如果变量 a 和 b 分别为 double 类型和 int 类型,则表达式 `(a = 6, b = 3 * (7 + 8) / 2, b += a)` 的计算结果为()。

A.
6
B.
21
C.
28
D.
不确定

正确答案C

解析详情

【答案】C

【考点】逗号表达式、复合赋值运算

【解析】 逗号表达式依次执行:1. a=6;2. b=3*(7+8)/2 = 3*15/2 = 22(整数除法);3. b+=a 即 b=22+6=28。表达式结果为最后一项的值 28。

【易错点】 计算 3*15/2 时未按整数除法取整,或对逗号表达式求值顺序不熟悉。

4 题(单选题

有关下面C++代码说法错误的是()。 // sumA()和sumB()用于求从1到N之和

#include <iostream>
using namespace std;
int sumA(int n) {
    int sum = 0;
    for (int i = 1; i < n + 1; i++)
        sum += i;
    return sum;
}
int sumB(int n) {
    if (n == 1)
        return 1;
    else
        return n + sumB(n - 1);
}
int main() {
    int n = 0;
    cin >> n;
    cout << sumA(n) << " " << sumB(n) << endl;
    return 0;
}
A.
sumA() 用循环方式求从 1 到 N 之和,sumB() 用递归方式求从 1 到 N 之和。
B.
默认情况下,如果输入正整数 1000,能实现求从 1 到 1000 之和。
C.
默认情况下,如果输入正整数 100000,能实现求从 1 到 100000 之和。
D.
一般说来,sumA() 的效率高于 sumB()。

正确答案C

解析详情

【答案】C

【考点】递归与循环的效率差异

【解析】 sumB 是递归实现,当 N=100000 时会因递归层数过深导致系统栈溢出。sumA 是循环实现,不受栈空间限制。故 C 选项描述“能实现”是错误的。

【易错点】 忽略递归在大规模数据下可能导致的内存栈溢出风险。

5 题(单选题

下面 C++ 代码以递归方式实现字符串反序,横线处应填上代码是()。

#include <iostream>
#include <string>
using namespace std;
string sReverse(string sIn) {
    if (sIn.length() <= 1) {
        return sIn;
    } else {
        return // 此处填写代码
    }
}
int main() {
    string sIn;
    cin >> sIn;
    cout << sReverse(sIn) << endl;
    return 0;
}
A.
sIn[sIn.length() - 1] + sReverse(sIn.substr(0, sIn.length() - 1));
B.
sIn[0] + sReverse(sIn.substr(1, sIn.length() - 1));
C.
sReverse(sIn.substr(0, sIn.length() - 1)) + sIn[sIn.length() - 1];
D.
sReverse(sIn.substr(1, sIn.length() - 1)) + sIn[sIn.length() - 1];

正确答案A

解析详情

【答案】A

【考点】递归算法实现

【解析】 反序字符串的递归逻辑为:取原串末尾字符作为首字符,再拼接剩余部分的反序结果。选项 A 正确体现了取出末尾字符并拼接剩余子串反序结果的逻辑。

【易错点】 混淆 substr 的参数含义,或未将末尾字符放在最前面。

6 题(单选题

印度古老的汉诺塔传说:创世时有三根金刚柱,其中一柱从下往上按照大小顺序摞着64片黄金圆盘,当圆盘逐一从一柱借助另外一柱全部移动到另外一柱时,宇宙毁灭。移动规则:在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。下面的C++代码以递归方式实现汉诺塔,横线处应填入代码是()。

#include <iostream>
using namespace std;
// 递归实现汉诺塔,将N个圆盘从A通过B移动C
// 圆盘从底到顶,半径必须从大到小
void Hanoi(string A, string B, string C, int N) {
    if (N == 1) {
        cout << A << " -> " << C << endl;
    } else {
        Hanoi(A, C, B, N - 1);
        cout << A << " -> " << C << endl;
        // 此处填写代码
    }
}

int main() {
    Hanoi("甲", "乙", "丙", 3);
    return 0;
}
A.
Hanoi(B, C, A, N - 2)
B.
Hanoi(B, A, C, N - 1)
C.
Hanoi(A, B, C, N - 2)
D.
Hanoi(C, B, A, N - 1)

正确答案B

解析详情

【答案】B

【考点】汉诺塔递归算法

【解析】 汉诺塔核心步骤:1. 将 N-1 个从 A 移到 B;2. 将第 N 个从 A 移到 C;3. 将 N-1 个从 B 移到 C。代码已完成前两步,最后一步应为 Hanoi(B, A, C, N-1)。

【易错点】 分不清辅助柱和目标柱在递归调用中的位置变化。

7 题(单选题

根据下面C++代码的注释,两个横线处应分别填入()。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool isOdd(int N) {
    return N % 2 == 1;
}
bool compare(int a, int b) {
    if (a % 2 == 0 && b % 2 == 1)
        return true;
    return false;
}

int main() {
    vector<int> lstA; // lstA是一个整型向量
    for (int i = 1; i < 100; i++)
        lstA.push_back(i);
    // 对lstA成员按比较函数执行结果排序
    sort(lstA.begin(), lstA.end(), ___); // 此处填写代码1
    vector<int> lstB;
    for (int i = 0; i < lstA.size(); i++) // lstB成员全为奇数
        if (___) // 此处填写代码2
            lstB.push_back(lstA[i]);
    cout << "lstA:";
    for (int i = 0; i < lstA.size(); i++)
        cout << lstA[i] << "";
    cout << endl;
    cout << "lstB:";
    for (int i = 0; i < lstB.size(); i++)
        cout << lstB[i] << "";
    cout << endl;
    return 0;
}
A.
Image
B.
Image
C.
Image
D.
Image

正确答案A

解析详情

【答案】A

【考点】STL 容器与排序算法

【解析】 sort 第三个参数为比较函数名 compare;循环内判断是否存入 lstB 的条件是元素为奇数,即需调用 isOdd(lstA[i])。选项 A 符合此语法逻辑。

【易错点】 对 sort 自定义排序函数的传参方式及 vector 遍历条件理解不深。

8 题(单选题

有关下面代码正确的是()。 // 在C++语言中,可以通过函数指针的形式,将一个函数作为另一个函数的参数。 // 具体来说:bool checkNum(bool (*Fx)(int), int N);声明了一个函数, // 其第一个参数是函数指针类型,指向一个接收一个int参数且返回值为bool的函数。

#include <iostream>
using namespace std;

bool isEven(int N) {
    return N % 2 == 0;
}
bool checkNum(bool (*Fx)(int), int N) {
    return Fx(N);
}
int main() {
    cout << checkNum(isEven, 10) << endl;
    return 0;
}
A.
checkNum() 函数定义错误。
B.
将 isEven 作为 checkNum() 参数将导致错误。
C.
执行后将输出 1。
D.
运行时触发异常。

正确答案C

解析详情

【答案】C

【考点】函数指针的应用

【解析】 checkNum 接收函数指针并调用。checkNum(isEven, 10) 等价于调用 isEven(10),由于 10 是偶数返回 true,cout 将输出 1。代码语法及逻辑均正确。

【易错点】 误以为函数指针作为参数是非法语法。

9 题(单选题

有关下面C++代码正确的是()。

#include <iostream>
using namespace std;

bool isOdd(int N) {
    return N % 2 == 1;
}
int Square(int N) {
    return N * N;
}
bool checkNum(bool (*Fx)(int), int x) {
    return Fx(x);
}
int main() {
    cout << checkNum(isOdd, 10) << endl; // 输出行A
    cout << checkNum(Square, 10) << endl; // 输出行B
    return 0;
}
A.
checkNum() 函数定义错误。
B.
输出行 A 的语句将导致编译错误。
C.
输出行 B 的语句将导致编译错误。
D.
该代码没有编译错误。

正确答案C

解析详情

【答案】C

【考点】函数指针类型匹配

【解析】 checkNum 的第一个参数要求是返回 bool 的函数指针,而 Square 函数返回类型是 int,二者签名不匹配,在 C++ 中会导致编译错误。

【易错点】 忽略了函数指针在类型匹配上的严格性,误认为 int 可以自动兼容 bool 返回值。

10 题(单选题

下面代码执行后的输出是()。

#include <iostream>
using namespace std;

int jumpFloor(int N) {
    cout << N << "#";
    if (N == 1 || N == 2) {
        return N;
    } else {
        return jumpFloor(N - 1) + jumpFloor(N - 2);
    }
}

int main() {
    cout << jumpFloor(4) << endl;
    return 0;
}
A.
4#3#2#2#4
B.
4#3#2#2#1#5
C.
4#3#2#1#2#4
D.
4#3#2#1#2#5

正确答案D

解析详情

【答案】D

【考点】递归求值过程追踪

【解析】 j(4)输出4#调j(3)+j(2);j(3)输出3#调j(2)+j(1);j(2)输出2#返回2;j(1)输出1#返回1;此时j(3)返回3。最后执行j(2)输出2#返回2。总输出4#3#2#1#2#5。

【易错点】 在递归展开过程中漏掉中间的输出字符或计算错最后的返回值。

11 题(单选题

下面代码中的 isPrimeA() 和 isPrimeB() 都用于判断参数 N 是否素数,有关其时间复杂度的正确说法是()。

#include <iostream>
#include <cmath>
using namespace std;

bool isPrimeA(int N) {
    if (N < 2)
        return false;
    for (int i = 2; i < N; i++)
        if (N % i == 0)
            return false;
    return true;
}
bool isPrimeB(int N) {
    if (N < 2)
        return false;
    int endNum = int(sqrt(N));
    for (int i = 2; i <= endNum; i++)
        if (N % i == 0)
            return false;
    return true;
}

int main() {
    cout << boolalpha;
    cout << isPrimeA(13) << " " << isPrimeB(13) << endl;
    return 0;
}
A.
isPrimeA() 的最坏时间复杂度是O(N)O(N),isPrimeB() 的最坏时间复杂度是O(logN)O(\log N),isPrimeB() 优于 isPrimeA()。
B.
isPrimeA() 的最坏时间复杂度是O(N)O(N),isPrimeB() 的最坏时间复杂度是O(N12)O(N^{\frac{1}{2}}),isPrimeB() 优于 isPrimeA()。
C.
isPrimeA() 的最坏时间复杂度是O(N12)O(N^{\frac{1}{2}}),isPrimeB() 的最坏时间复杂度是O(N)O(N),isPrimeA() 优于 isPrimeB()。
D.
isPrimeA() 的最坏时间复杂度是O(logN)O(\log N),isPrimeB() 的最坏时间复杂度是O(N)O(N),isPrimeA() 优于 isPrimeB()。

正确答案B

解析详情

【答案】B

【考点】时间复杂度分析

【解析】 isPrimeA 循环 N 次,最坏复杂度为 O(N);isPrimeB 循环根号 N 次,最坏复杂度为 O(N^{1/2})。显然 isPrimeB 的效率优于 isPrimeA。

【易错点】 误将根号 N 的复杂度记为 log N。

12 题(单选题

下面代码用于归并排序,其中 merge() 函数被调用次数为()。

#include <iostream>
using namespace std;

void mergeSort(int * listData, int start, int end);
void merge(int * listData, int start, int middle, int end);

void mergeSort(int * listData, int start, int end) {
    if (start >= end)
        return;
    int middle = (start + end) / 2;
    mergeSort(listData, start, middle);
    mergeSort(listData, middle + 1, end);
    merge(listData, start, middle, end);
}

void merge(int * listData, int start, int middle, int end) {
    int leftSize = middle - start + 1;
    int rightSize = end - middle;

    int * left = new int[leftSize];
    int * right = new int[rightSize];
    for (int i = 0; i < leftSize; i++)
        left[i] = listData[start + i];
    for (int j = 0; j < rightSize; j++)
        right[j] = listData[middle + 1 + j];

    int i = 0, j = 0, k = start;
    while (i < leftSize && j < rightSize) {
        if (left[i] <= right[j]) {
            listData[k] = left[i];
            i++;
        } else {
            listData[k] = right[j];
            j++;
        }
        k++;
    }

    while (i < leftSize) {
        listData[k] = left[i];
        i++;
        k++;
    }
    while (j < rightSize) {
        listData[k] = right[j];
        j++;
        k++;
    }
    delete[] left;
    delete[] right;
}

int main() {
    int lstA[] = {1, 3, 2, 7, 11, 5, 3};
    int size = sizeof(lstA) / sizeof(lstA[0]);
    mergeSort(lstA, 0, size - 1); // 对lstA执行归并排序

    for (int i = 0; i < size; i++)
        cout << lstA[i] << "";
    cout << endl;
    return 0;
}
A.
0
B.
1
C.
6
D.
7

正确答案C

解析详情

【答案】C

【考点】分治算法与归并排序

【解析】 归并排序中 merge 在合并阶段调用。对于 7 个元素,递归分解产生的合并操作次数等于树的非叶节点数,即 7-1 = 6 次。具体为每次 mergeSort 产生左右两个子问题后的合并过程。

【易错点】 混淆了递归调用 mergeSort 的次数与执行合并 merge 的次数。

13 题(单选题

在上题的归并排序算法中,mergeSort(listData, start, middle); 和 mergeSort(listData, middle + 1, end); 涉及到的算法为()。

A.
搜索算法
B.
分治算法
C.
贪心算法
D.
递推算法

正确答案B

解析详情

【答案】B

【考点】分治算法思想

【解析】 归并排序通过“分解-解决-合并”的步骤处理问题,将大问题划分为同类的子问题递归求解,是典型的分治(Divide and Conquer)算法思想。

【易错点】 将递归实现误认为是简单的递推或搜索算法。

14 题(单选题

归并排序算法的基本思想是()。

A.
将数组分成两个子数组,分别排序后再合并。
B.
随机选择一个元素作为枢轴,将数组划分为两个部分。
C.
从数组的最后一个元素开始,依次与前一个元素比较并交换位置。
D.
比较相邻的两个元素,如果顺序错误就交换位置。

正确答案A

解析详情

【答案】A

【考点】归并排序基本原理

【解析】 归并排序的核心思想是将待排序数组递归地分成两部分,分别完成排序后,再通过有序合并操作将结果拼成完整的有序序列。

【易错点】 混淆归并排序与快速排序(选枢轴划分)或冒泡排序(相邻交换)的区别。

15 题(单选题

有关下面代码的说法正确的是()。

#include <iostream>

class Node {
    public:
    int Value;
    Node *Next;

    Node(int Val, Node *Nxt = nullptr) {
        Value = Val;
        Next = Nxt;
    }
    };
    int main() {
        Node *firstNode = new Node(10);
        firstNode->Next = new Node(100);
        firstNode->Next->Next = new Node(111, firstNode);
        return 0;
    }
A.
上述代码构成单向链表。
B.
上述代码构成双向链表。
C.
上述代码构成循环链表。
D.
上述代码构成指针链表。

正确答案C

解析详情

【答案】C

【考点】链表数据结构

【解析】 代码中 firstNode->Next->Next = new Node(111, firstNode) 创建了第三个节点,并将其 Next 指针指向头节点 firstNode,构成了首尾相连的循环链表。

【易错点】 未注意到 Node 构造函数的第二个参数将链表尾部重新指向了头部。

判断题(每题 2 分)

1 题(判断题

TCP/IP 的传输层的两个不同的协议分别是 UDP 和 TCP。

正确答案正确

解析详情

【答案】正确

【考点】传输层协议

【解析】 TCP(传输控制协议)和 UDP(用户数据报协议)是 TCP/IP 协议栈传输层中最重要的两个核心协议。

【易错点】 误认为 HTTP 或 IP 属于传输层协议。

2 题(判断题

在特殊情况下流程图中可以出现三角框和圆形框。

正确答案错误

解析详情

【答案】错误

【考点】流程图标准规范

【解析】 标准程序流程图中,矩形代表处理,菱形代表判断,平行四边形代表输入输出。三角形和圆形并非标准的处理逻辑框。

【易错点】 认为流程图可以根据个人喜好随意使用各种非标准形状。

3 题(判断题

找出自然数 N 以内的所有质数,常用算法有埃氏筛法和线性筛法,其中埃氏筛法效率更高。

正确答案错误

解析详情

【答案】错误

【考点】质数筛法效率对比

【解析】 埃氏筛法的复杂度为 O(N log log N),而线性筛法(欧拉筛)通过让每个合数只被其最小质因子筛掉一次,实现了 O(N) 的线性复杂度,效率更高。

【易错点】 记忆混淆,误以为埃氏筛法比线性筛法快。

4 题(判断题

在 C++ 中,可以使用二分法查找链表中的元素。

正确答案错误

解析详情

【答案】错误

【考点】链表的访问特性

【解析】 二分查找依赖于随机访问特性。链表只能顺序访问,获取中间元素需 O(N) 时间,因此在链表上使用二分法不具备效率优势,通常不这样使用。

【易错点】 认为只要序列有序就可以直接使用二分查找,忽略了底层存储结构的影响。

5 题(判断题

在 C++ 中,通过恰当的实现,可以将链表首尾相接,形成循环链表。

正确答案正确

解析详情

【答案】正确

【考点】链表结构实现

【解析】 循环链表是通过将单链表最后一个节点的 next 指针指向第一个节点来实现的,在 C++ 中只需合理修改指针指向即可完成。

【易错点】 对链表指针操作的灵活性缺乏认识。

6 题(判断题

贪心算法的解可能不是最优解。

正确答案正确

解析详情

【答案】正确

【考点】贪心算法局限性

【解析】 贪心算法在每一步只寻求当前局部最优解,而局部最优的叠加并不一定能保证最终得到全局最优解。

【易错点】 混淆贪心算法与动态规划的区别,认为贪心总能得到最优解。

7 题(判断题

一般说来,冒泡排序算法优于归并排序。

正确答案错误

解析详情

【答案】错误

【考点】排序算法复杂度

【解析】 冒泡排序的平均时间复杂度为 O(N^2),而归并排序为 O(N log N)。在处理大规模数据时,归并排序的效率远高于冒泡排序。

【易错点】 由于冒泡排序易于理解和编写,误认为其在所有场景下都性能优秀。

8 题(判断题

C++语言中的 qsort 库函数是不稳定排序。

正确答案正确

解析详情

【答案】正确

【考点】排序算法稳定性

【解析】 C 标准库中的 qsort 通常采用快速排序实现。快速排序在交换过程中可能改变相等元素的相对位置,因此是不稳定的排序算法。

【易错点】 误以为标准库提供的排序函数默认都是稳定的。

9 题(判断题

质数的判定和筛法的目的并不相同,质数判定旨在判断特定的正整数是否为质数,而质数筛法意在筛选出范围内的所有质数。

正确答案正确

解析详情

【答案】正确

【考点】质数相关算法目的

【解析】 质数判定侧重于检查单个数字的属性,而筛法侧重于批量提取某一范围内的所有质数,二者的应用场景和关注点不同。

【易错点】 认为两者都是为了处理质数,在功能目的上没有本质区别。

10 题(判断题

下面的 C++ 代码执行后将输出 0 5 1 6 2 3 4 。

#include <iostream>
#include <algorithm>
using namespace std;

bool compareModulo5(int a, int b) {
    return a % 5 < b % 5;
}

int main() {
    int lst[7];
    for (int i = 0; i < 7; i++)
        lst[i] = i;

    // 对序列所有元素按compareModulo5结果排序
    sort(lst, lst + 7, compareModulo5);

    for (int i = 0; i < 7; i++)
        cout << lst[i] << " ";
    cout << endl;
    return 0;
}

正确答案正确

解析详情

【答案】正确

【考点】自定义排序规则应用

【解析】 代码按元素对 5 取模结果排序:0%5=0, 5%5=0, 1%5=1, 6%5=1, 2%5=2, 3%5=3, 4%5=4。排序后结果为 0 5 1 6 2 3 4。

【易错点】 在手动模拟排序过程时,对取模运算的余数计算错误或混淆了 sort 的执行结果。