试卷解析 · 理解每一步
2023-12-Level-5
2023-12-Level-5
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
下面C++代码用于求斐波那契数列,该数列第1、2项为1,以后各项均是前两项之和。下面有关说法错误的是()。
int fibroA(int N)
{
if (N == 1 || N == 2)
{
return 1;
return fibroA(N - 1) + fibroA(N - 2);
}
int fibroB(int N)
{
if (N == 1 || N == 2)
{
return 1;
int last2 = 1, last1 = 1;
int nowVal = 0;
for (int i = 2; i < N; i++)
{
nowVal = last1 + last2;
last2 = last1;
last1 = nowVal;
}
return nowVal;
}
}
}正确答案C
解析详情
fibroA() 采用递归方式,虽然代码简洁且符合数学定义,但存在大量的重复计算,时间复杂度呈指数级增长;fibroB() 采用循环方式,时间复杂度为 O(N),执行效率远高于递归方式。选项 C 错误地认为递归效率更高。
第 2 题(单选题,2 分)
下面C++代码以递归方式实现合并排序,并假设 merge(int T[],int R[],int s,int m,int t)函数将有序(同样排序规则)的T[s..m]和T[m+1..t]归并到R[s..t]中。横线处应填上代码是()。
void mergeSort(int SList[], int TList[], int s, int t, int len)
{
if (s == t)
{
TList[s] = SList[s];
return;
}
int *T2 = new int[len]; // 保存中间结果
int m = (s + t) / 2;
;
merge(T2, SList, s, m, t);
delete T2;
return;
}正确答案C
解析详情
归并排序的核心是将区间 `[s, t]` 分为左半部分 `[s, m]` 和右半部分 `[m+1, t]` 分别进行递归排序,其中 `m = (s + t) / 2`。选项 C 正确划分了这两个子区间。选项 A 区间重叠,B 和 D 区间划分有漏项或错误。
第 3 题(单选题,2 分)
阅读下面的 C++ 代码,执行后其输出是()。
int stepCount = 0;
int fracA(int N)
{
stepCount += 1;
cout << stepCount << "-";
int rtn = 1;
for (int i = 1; i <= N; i++)
{
rtn *= i;
return rtn;
}
}
int fracB(int N)
{
stepCount += 1;
cout << stepCount << "-";
if (N == 1)
{
return 1;
return N * fracB(N - 1);
}
}
int main()
{
cout << fracA(5);
cout << "< $\leq$$\geq$>";
cout << fracB(5);
return 0;
}正确答案D
解析详情
`fracA(5)` 首先将 `stepCount` 增加到 1,打印 `1-`,循环中遇到 `return` 立即返回 1。接着打印分隔符。然后调用 `fracB(5)`,其递归调用会依次将 `stepCount` 增加:`fracB(5)` 增加到 2,`fracB(4)` 到 3...直到 `fracB(1)` 到 6,依次打印 `2-3-4-5-6-`。由于代码中存在明显的语法或逻辑冗余(如 `return` 后还有代码),根据选项 D 的模式推断其输出路径。
第 4 题(单选题,2 分)
下面的C++用于对lstA排序,使得偶数在前奇数在后,横线处应填入()。
bool isEven(int N)
{
return N % 2 == 0;
}
void swap(int &a, int &b)
{
int t;
t = a, a = b, b = t;
return;
}
void sortA(int lstA[], int n)
{
int i, j, t;
for (i = n - 1; i > 0; i--)
for (j = 0; j < i; j++)
if (______)
swap(lstA[j], lstA[j + 1]);
}正确答案A
解析详情
题目要求偶数在前、奇数在后。在冒泡排序中,如果前一个数 `lstA[j]` 是奇数且后一个数 `lstA[j+1]` 是偶数,则两者的相对位置不符合要求,需要进行交换。故填入 `!isEven(lstA[j]) && isEven(lstA[j+1])`。
第 5 题(单选题,2 分)
下面的C++代码用于将字符串保存到带头节点的双向链表中,并对重复的串计数,然后将最新访问的串的节点放在链头便于查找。横线处应填入代码是()。
typedef struct Node{
string str;
int ref;
struct Node *next, *prev;
} Node;
Node * Insert(Node *pHead, string s)
{
Node *p = pHead->next;
Node *q;
while(p){
if(p->str == s){
p->ref++;
p->next->prev = p->prev;
p->prev->next = p->next;
break;
}
p=p->next;
}
if(!p){
p = new Node;
p->str = s;
p->ref=0;
p->next = p->prev = NULL;
}
// 待填空
pHead->next = p, p->prev = pHead;
return pHead;
}正确答案B
解析详情
代码逻辑是将节点 `p` 插入到头节点 `pHead` 之后。如果链表已有后续节点(`pHead->next` 不为空),需要先处理 `p` 与原第一个节点的连接,即 `p->next = pHead->next` 和 `pHead->next->prev = p`。如果直接写 C 而不判断 `pHead->next` 是否存在,在空链表插入时会发生空指针引用。故选 B。
第 6 题(单选题,2 分)
有关下⾯C++代码说法正确的是( )。
int rc;
int foo(int x, int y)
{
int r;
if (y == 0)
r = x;
else {
r = foo(y, x % y);
rc++;
}
return r;
}正确答案A
解析详情
该函数 `foo` 实现了求最大公约数(GCD)的欧几里得算法。递归深度(`rc` 的最终值)与 `log(max(x, y))` 成比例,对于 `x < 10`,递归次数极少,绝不可能超过 20。选项 B 错误,该算法总会收敛到 `y=0`;C 和 D 错误,函数返回的是最大公约数,而不是质因子或最小公倍数。
第 7 题(单选题,2 分)
下面的C++代码实现对list的快速排序,有关说法,错误的是()。
vector<int> operator +(vector<int>lA,vector<int>lB)
{
vector<int>lst;
for (int i = 1; i < lA.size(); i++)
{
lst.push_back(lA[i]);
for (int i = 1; i < lB.size(); i++)
{
lst.push_back(lB[i]);
return lst;
}
}
vector<int>qSort(vector<int>lst)
{
if (lst.size() < 2)
{
return lst;
}
int pivot = lst[0];
vector<int>less, greater;
for (int i = 1; i < lst.size(); i++)
{
if (lst[i] <= pivot) less.push_back(lst[i]);
else greater.push_back(lst[i]);
for (int i = 1; i < lst.size(); i++)
{
if (lst[i] <= pivot) less.push_back(lst[i]);
else greater.push_back(lst[i]);
}
}
return _____;
}正确答案C
解析详情
快速排序的思想是将数组分为小于主元、等于主元、大于主元的三部分。本题中 `pivot` 是选定的主元,`less` 包含小于等于它的元素,`greater` 包含大于它的元素。递归处理后,应按“小于部分 + 主元 + 大于部分”顺序拼接,且由于重载了 `vector` 加法,需将 `pivot` 转为 `vector` 类型。故选 C。
第 8 题(单选题,2 分)
下面C++代码中的 `isPrimeA()` 和 `isPrimeB()` 都用于判断参数N是否素数,有关其时间复杂度的正确说法是( )。
bool isPrimeA(int N)
{
if (N < 2)
return false;
for (int i = 2; i <= N / 2; i++)
if (N % i == 0)
return false;
return true;
}
bool isPrimeB(int N)
{
if (N < 2)
return false;
for (int i = 2; i <= sqrt(N); i++)
if (N % i == 0)
return false;
return true;
}正确答案B
解析详情
`isPrimeA` 循环上限为 `N/2`,复杂度为 O(N);`isPrimeB` 循环上限为 `sqrt(N)`,复杂度为 O(√N)。由于 √N 远小于 N(当 N 较大时),故 `isPrimeB` 的效率远优于 `isPrimeA`。选项 B 正确反映了这一性能对比。
第 9 题(单选题,2 分)
下面C++代码用于有序 list 的二分查找,有关说法错误的是()。
int _binarySearch(vector<int>lst, int Low, int High, int Target)
{
if (Low > High)
{
return -1;
}
int Mid = (Low + High) / 2;
if (Target == lst[Mid])
{
return Mid;
}
else if (Target < lst[Mid])
{
return _binarySearch(lst, Low, Mid - 1, Target);
}
else
{
return _binarySearch(lst, Mid + 1, High, Target);
}
}
int bSearch(vector<int>lst, int Val)
{
return _binarySearch(lst, 0, lst.size(), Val);
}正确答案D
解析详情
二分查找通过每次将搜索区间减半来定位元素,这属于“分治算法”和“二分法”的应用,同时也使用了递归方式实现。动态规划主要用于处理具有重叠子问题和最优子结构性质的问题,二分查找并不涉及这些特性。故 D 说法错误。
第 10 题(单选题,2 分)
在上题的 _binarySearch_ 算法中,如果 lst 中有 N 个元素,其时间复杂度是( )。
正确答案B
解析详情
二分查找每进行一次比较,搜索范围就缩小为原来的一半。对于长度为 N 的有序列表,最多进行 `log2(N)` 次比较即可得出结果或确认不存在。因此,其时间复杂度是 O(log N)。
第 11 题(单选题,2 分)
下面的C++代码使用数组模拟整数加法,可以处理超出大整数范围的加法运算。横线处应填入代码是()。
vector<int> operator + (vector<int> a, vector<int> b)
{
vector<int> c;
int t = 0;
for(int i = 0; i < a.size() || i < b.size(); i++)
{
if(i < a.size()) t = t + a[i];
if(i < b.size()) t = t + b[i];
______;
}
if(t) c.push_back(t);
return c;
}正确答案D
解析详情
在高精度加法模拟中,`t` 代表当前位的和(包含前一号位的进位)。存入当前位的值应是 `t % 10`(取个位数),而留给下一位的进位应是 `t / 10`。故选 D。
第 12 题(单选题,2 分)
有关下面 C++ 代码的说法正确的是()。
class Node
{
public:
int Value;
Node* Prev;
Node* Next;
Node(int Val, Node* Prv = NULL, Node* Nxt = NULL);
};
Node::Node(int Val, Node* Prv, Node* Nxt)
{
this->Value = Val;
this->Prev = Prv;
this->Next = Nxt;
}
int main()
{
Node firstNode = Node(10);
firstNode.Next = new Node(100, &firstNode);
firstNode.Next->Next = new Node(111, firstNode.Next);
}正确答案B
解析详情
代码定义了包含 `Prev`(前驱)和 `Next`(后继)两个指针的 `Node` 类。在 `main` 函数中,创建新节点时传入了前一个节点的地址作为 `Prv` 参数,从而建立了双向链接。这符合双向链表的定义。故选 B。
第 13 题(单选题,2 分)
通讯卫星在通信网络系统中主要起到()的作用。
正确答案B
解析详情
由于地球曲率和障碍物的影响,地面微波信号无法长距离直线传输。通讯卫星悬挂在高空,接收地面发出的信号并将其转发(中继)回地面其他位置,起到“空间中继站”的作用。故选 B。
第 14 题(单选题,2 分)
小杨想编写一个判断任意输入的整数 N 是否为素数的程序,下面哪个方法不合适?()
正确答案C
解析详情
埃氏筛和线性筛用于批量筛选素数;枚举法(试除法)用于判定单个整数是否为素数。而“二分答案”要求解空间具有单调性,通常用于求解最大值或最小值问题,对于素数这种不具有连续单调分布性质的判断问题完全不适用。故选 C。
第 15 题(单选题,2 分)
下面的排序算法都要处理多趟数据,哪种排序算法不能保证在下一趟处理时从待处理数据中选出最大或最小的数据?()
正确答案B
解析详情
选择排序、堆排序和冒泡排序在每趟结束后都能确定一个当前未排序数据中的最大(或最小)值并将其放到最终位置。而快速排序每趟(Partition)仅能确定主元(Pivot)的最终位置,主元不一定是当前待处理数据中的最大或最小值。故选 B。
判断题
第 1 题(判断题,2 分)
归并排序的时间复杂度是。()
正确答案正确
解析详情
归并排序采用分治法,将规模为 N 的问题分为两个 N/2 的子问题,且合并过程需要 O(N) 时间。根据主定理,其时间复杂度在最坏、平均和最好情况下均为 O(N log N)。
第 2 题(判断题,2 分)
小杨在生日聚会时拿一块H*W的巧克力招待来的K个小朋友,保证每位小朋友至少能获得一块相同大小的巧克力。那么小杨想分出来最大边长的巧克力可以使用二分法。()
正确答案错误
解析详情
设正方形巧克力的边长为 x,则能分出的块数随着 x 的增大而单调递减。这种解空间具有单调性的最值问题可以通过“二分边长 x”来快速求解。题干描述符合二分答案的应用场景。
第 3 题(判断题,2 分)
以下C++代码能以递归方式实现斐波那契数列,该数列第1、2项为1,以后各项均是前两项之和。()
int Fibo(int N)
{
if (N == 1 || N == 2)
return 1;
else
{
int m = fiboA(N - 1);
int n = fiboB(N - 2);
return m + n;
}
}正确答案错误
解析详情
在递归实现中,函数必须调用自身(即相同的函数名)。代码中定义的函数名为 `Fibo`,但在函数体内调用的却是 `fiboA` 和 `fiboB`,这会导致编译错误或逻辑不属于递归实现。故题干断言不成立。
第 4 题(判断题,2 分)
贪心算法可以达到局部最优,但可能不是全局最优解。()
正确答案正确
解析详情
贪心算法的核心在于每一步都做出当前看起来最优的选择。虽然这保证了每一步的局部最优,但对于许多问题(如非特殊面值的找零问题),局部最优的选择并不一定能推导出全局最优的结果。
第 5 题(判断题,2 分)
小杨设计了一个拆数程序,它能够将任意的非质数自然数 N 转换成若干个质数的乘积,这个程序是可以设计出来的。()
正确答案正确
解析详情
根据算术基本定理,每一个大于 1 的自然数,要么本身是质数,要么可以唯一地分解为质因数的乘积。在计算机程序中,可以通过简单的试除法实现这一分解逻辑。故该程序是可以设计出来的。
第 6 题(判断题,2 分)
插入排序有时比快速排序时间复杂度更低。()
正确答案正确
解析详情
在最坏情况下,快速排序为 O(N^2) 而插入排序也是 O(N^2)。但在最好情况下(即序列已经基本有序),插入排序仅需 O(N) 的比较次数,而快速排序即便在最好情况下也通常需要 O(N log N)。故题干描述正确。
第 7 题(判断题,2 分)
下面的 C++ 代码能实现十进制正整数 N 转换为八进制并输出。()
char s[10];
int main()
{
int N;
cin >> N;
string rst = "";
while (N != 0)
{
s[0] = N & 8 + '0';
rst += string(s);
N /= 8;
}
cout << rst << endl;
return 0;
}正确答案错误
解析详情
代码中 `N & 8` 是错误的取位操作,八进制取位应使用 `N % 8`。此外,`s[0]` 的赋值方式和 `rst` 的拼接逻辑会导致输出顺序颠倒(应先取低位,最后逆序输出),且位运算符 `&` 的优先级低于 `+`,会导致逻辑完全错误。
第 8 题(判断题,2 分)
对数组 int arr[] = {2, 6, 3, 5, 4, 8, 1, 0, 9, 10} 执行 sort(arr, arr+10),则执行后 arr 中的数据调整为 {0, 1, 2, 3, 4, 5, 6, 8, 9, 10}。()
正确答案正确
解析详情
`sort(arr, arr+10)` 对数组 `arr` 的前 10 个元素进行默认的升序排序。原数组中包含 0 到 10 之间的数字(缺少 7),排序后的结果确实是将这些数字按从小到大排列。故断言正确。
第 9 题(判断题,2 分)
小杨想写一个程序来算出正整数N有多少个因数,经过思考他写出了一个重复没有超过N/2次的循环就能够算出来了。()
正确答案正确
解析详情
求正整数 N 的因数,最基础的方法是枚举到 N,而由于除了 N 本身,最大的因数不可能超过 N/2,因此循环到 N/2 即可找全除 N 以外的所有因数。实际上优化到 `sqrt(N)` 效率更高。题干中“不超过 N/2 次”是完全可以实现的。
第 10 题(判断题,2 分)
同样的整数序列分别保存在单链表和双向链中,这两种链表上的简单冒泡排序的复杂度相同。()
正确答案正确
解析详情
冒泡排序的复杂度由比较和交换的次数决定,对于长度为 N 的序列,比较次数均为 O(N^2)。无论是单链表还是双向链表,在交换相邻节点或其数值时的时间开销均为常数阶。故两者的总时间复杂度相同。