CCF-GESP 等级考试 2025年6月认证C++五级真题解析

1 单选题(每题 2 分,共 30 分)

第1题 与数组相比,链表在(   )操作上通常具有更高的效率。

A. 随机访问元素                                                   B. 查找指定元素

C. 在已知位置插入或删除节点                             D. 遍历所有元素

解析:答案C。与数组相比,链表在插入和删除操作上通常具有更高的效率。这是因为链表采用非连续的链式存储结构,在插入或删除元素时仅需调整相邻节点的指针,无需移动大量元素;而数组基于连续内存空间,插入或删除需移动后续元素以维持连续性,导致更高时间复杂度。故选C

第2题 下面C++代码实现双向链表。函数 is_empty() 判断链表是否为空,如链表为空返回 true ,否则返回 false 。横线处不能填写(   )。

  1. // 节点结构体
  2. struct Node {
  3.     int data;
  4.     Node* prev;
  5.     Node* next;
  6. };
  7. // 双向链表结构体
  8. struct DoubleLink {
  9.     Node* head;
  10.     Node* tail;
  11.     int size;
  12.     DoubleLink() {
  13.         head = nullptr;
  14.         tail = nullptr;
  15.         size = 0;
  16.     }
  17.     ~DoubleLink() {
  18.         Node* curr = head;
  19.         while (curr) {
  20.             Node* next = curr->next;
  21.             delete curr;
  22.             curr = next;
  23.         }
  24. }
  25.     // 判断链表是否为空
  26.     bool is_empty() const {
  27.         _______________________
  28.     }
  29. };

A. return head == nullptr;                                           B. return tail == nullptr;

C. return head.data == 0;                                           D. return size == 0;

解析:答案C。要判断双向链表是否空,按14~18行构造函数,在给定的双向链表实现中,is_empty() 函数可以有多种正确的实现方式。以下是可能的正确填写选项:

  1. return head == nullptr;
  2. return tail == nullptr;
  3. return head == nullptr && tail == nullptr;
  4. return size == 0;

所以不能用head.data == 0判断。故选C

第3题 基于上题代码正确的前提下,填入相应代码完善append(),用于在双向链表尾部增加新节点,横线上应填写(   )。

  1. void append(int data) {
  2.     Node* newNode = new Node{data, nullptr, nullptr};
  3.     if (is_empty()) {
  4.         head = tail = newNode; }
  5.     else {
  6.         _______________________
  7.     }
  8.     ++size;
  9. }

A.

  1. tail->next = newNode;

B.

  1. newNode->prev = tail;
  2. tail = newNode;

C.

  1. tail = newNode;
  2. newNode->prev = tail;
  3. tail->next = newNode;

D.

  1. tail->next = newNode;
  2. newNode->prev = tail;
  3. tail = newNode;

解析:答案D。函数名为append,应该是追加,即新节点添加在链表尾部。尾节点的后继指向新节点(tail->next = newNode;),新节点的前驱为尾节点(newNode->prev = tail;),置新节点为尾节点(tail = newNode;)。故选D

第4题 下列C++代码用循环链表解决约瑟夫问题,即假设n个人围成一圈,从第一个人开始数,每次数到第k个的人就出圈,输出最后留下的那个人的编号。横线上应填写(   )。

  1. struct Node {
  2.     int data;
  3.     Node* next;
  4. };
  5. Node* createCircularList(int n) {
  6.     Node* head = new Node{1, nullptr};
  7.     Node* prev = head;
  8.     for (int i = 2; i <= n; ++i) {
  9.         Node* node = new Node{i, nullptr};
  10.         prev->next = node;
  11.         prev = node;
  12.     }
  13.     prev->next = head;
  14.     return head;
  15. }
  16. int fingLastSurvival(int n, int k) {
  17.     Node* head = createCircularList(n);
  18.     Node* p = head;
  19.     Node* prev = nullptr;
  20.     while (p->next != p) {
  21.         for (int count = 1; count < k; ++count) {
  22.             prev = p;
  23.             p = p->next;
  24.         }
  25.         _______________________
  26.     }
  27.     cout << "最后留下的人编号是: " << p->data << endl;
  28.     delete p;
  29.     return 0;
  30. }

A.

  1. prev->next = p->next;
  2. delete p;
  3. p = prev->next;

B.

  1. delete p;
  2. prev->next = p->next;
  3. p = prev->next;

C.

  1. delete p;
  2. p = prev->next;
  3. prev->next = p->next;

D.

  1. prev->next = p->next;
  2. p = prev->next;
  3. delete p;

解析:答案A。这是一个单向循环链表,第28行处要要删除(每次数到第k个的人就出圈)节点p,需要先将p的前驱的后继设为p的后继,然后才能删除pA.正确。B.p删除后获得p的后继,错误。C.p前驱的后继为pp删除了链表指向错误。D.删除的是p的后继节点,错误。故选A

第5题 下列C++代码判断一个正整数是否是质数,说法正确的是(   )。

  1. bool is_prime(int n) {
  2.     if (n <= 1)
  3.         return false;
  4.     if (n == 2 || n == 3 || n == 5)
  5.         return true;
  6.     if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0)
  7.         return false;
  8.     int i = 7;
  9.     int step = 4;
  10.     int finish_number = sqrt(n) + 1;
  11.     while (i <= finish_number) {
  12.         if (n % i == 0)
  13.             return false;
  14.         i += step;
  15.         step = 6 - step;
  16.     }
  17.     return true;
  18. }

A. 代码存在错误,比如5是质数,但因为 5 % 5 余数是0返回了false

B. finish_number 的值应该是n / 2,当前写法将导致错误

C. 当前 while 循环正确的前提是:所有大于3的质数都符合 6k±1 形式

D. while 循环修改如下,其执行效果和执行时间相同。

  1. for (int i = 2; i < finish_number; i++) {
  2.     if (n % i == 0)
  3.         return false;
  4. }
  5. return true;

解析:答案C。本题中的程序应用了质数的6k±1规则:除了23之外的所有质数都可以表示为6k±1的形式,因为若数n能被23整除,则n为合数;若数n不能被23整除,则其除以6的余数不能是0234,只能是15(例如5571115),因此必然属于6k±1的形式,C.正确。5因第4行条件成立会返回true,所以A.错误;求质数枚举因数的上限为\sqrt{n},而不是n/2B.错误;原程序只枚举了小\sqrt{n}+1的6k±1形式的数,D.选项程序枚举了2 ~ \sqrt{n}的所有数,原程序时间会更快一些,D.错误。故选C

第6题 下列C++代码用两种方式求解两个正整数的最大公约数,说法错误的是(   )。

  1. int gcd0(int big, int small) {
  2.     if (big < small) {
  3.         swap(big, small);
  4.     }
  5.     if (big % small == 0) {
  6.         return small;
  7.     }
  8.     return gcd0(small, big % small);
  9. }
  10. int gcd1(int big, int small) {
  11.     if (big < small) {
  12.         swap(big, small);
  13.     }
  14.     for (int i = small; i >= 1; --i) {
  15.         if (big % i == 0 && small % i == 0)
  16.             return i;
  17.     }
  18.     return 1;
  19. }

A. gcd0()函数的时间复杂度为O(log n)

B. gcd1() 函数的时间复杂度为O(n)

C. 一般说来,gcd0()的效率高于gcd1()

D. gcd1() 中的代码 for (int i = small; i >= 1; --i) 应该修改为 for (int i = small; i > 1; --i)

解析:答案DA.gcd0()函数为辗转相除法递归求最大公约数,辗转相除法(欧几里得算法)的时间复杂度为‌O(log(min(a, b)))‌,其中ab为输入的两个整数,设n=min(a,b),时间复杂度为O(log n),正确;B.gcd1()只有一重循环,时间复杂度为O(n),正确gcd0()时间复杂度为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值