C++GESP5级202409解析

· · 算法·理论

选择题

1. 关于链表和数组的描述,错误的是(C)。

2. 通过(D)操作,能完成在双向循环链表结点p 之后插入结点s 的功能(其中next 域为结点的直接后继, prev 域为结点的直接前驱)。

3. 对下面两个函数,说法错误的是(C)。

int sumA(int n) {
  int res = 0;
  for (int i = 1; i <= n; i++) {
    res += i;
  }
  return res;
}
int sumB(int n) {
  if (n == 1)
      return 1;
  int res = n + sumB(n - 1);
  return res;
}

4. 有如下函数fun ,则fun(20, 12) 的返回值为(C)。

int fun(int a, int b) {
  if (a % b == 0)
    return b;
  else
    return fun(b, a % b);
}

5. 下述代码实现素数表的埃拉托斯特尼筛法,筛选出所有小于等于n 的素数,则横线上应填的最佳代码是( C).

void sieve_Eratosthenes(int n) {
  vector<bool> is_prime(n + 1, true);
  vector<int> primes;
for (int i = 2; i * i <= n; i++) {
  if (is_prime[i]) {
    primes.push_back(i);__________ { // 在此处填入代码
      is_prime[j] = false;
    }
  }
}
for (int i = sqrt(n) + 1; i <= n; i++) {
  if (is_prime[i]) {
    primes.push_back(i);
    }
  }
return primes;
}

6. 下述代码实现素数表的线性筛法,筛选出所有小于等于n 的素数,则横线上应填的代码是(A )

vector<int> sieve_linear(int n) {
  vector<bool> is_prime(n + 1, true);
    vector<int> primes; 3 4 5 6 7 8
  for (int i = 2; i <= n / 2; i++) {   
    if (is_prime[i])   
      primes.push_back(i);   
    __________ {   //在此处填入代码
      is_prime[i * primes[j]] = 0;   
      if (i % primes[j] == 0)   
          break;   
    }   
}   
for (int i = n / 2 + 1; i <= n; i++) {   
  if (is_prime[i])   
    primes.push_back(i);   
}   
  return primes;
}

7. 下面函数可以将n 的所有质因数找出来,其时间复杂度是(C )。

#include <iostream>
#include <vector>
vector<int> get_prime_factors(int n) {
  vector<int> factors;
  while (n % 2 == 0) {
    factors.push_back(2);
    n /= 2;
  }
  for (int i = 3; i * i <= n; i += 2) {
    while (n % i == 0) {
      factors.push_back(i);
      n /= i;
    }
  }
  if (n > 2) {
    factors.push_back(n);
  }
  return factors;
}

8. 现在用如下代码来计算 x^n (n个x相乘),其时间复杂度为(C)。

作者被名字骗了一开始以为是快速幂
double quick_power(double x, unsigned n) {
  if (n == 0) return 1;
  if (n == 1) return x;
  return quick_power(x, n / 2) * quick_power(x, n / 2) * ((n & 1) ? x : 1);
}

9. 假设快速排序算法的输入是一个长度为 n 的已排序数组,且该快速排序算法在分治过程总是选择第一个元素 作为基准元素。下面选项(C )描述的是在这种情况下的快速排序行为。

10. 考虑以下C++代码实现的归并排序算法:

void merge(int arr[], int left, int mid, int right) {
  int n1 = mid - left + 1;
  int n2 = right - mid;
  int L[n1], R[n2];
  for (int i = 0; i < n1; i++)
    L[i] = arr[left + i];
  for (int j = 0; j < n2; j++)
    R[j] = arr[mid + 1 + j];
  int i = 0, j = 0, k = left;
  while (i < n1 && j < n2) {
      if (L[i] <= R[j]) {
        arr[k] = L[i];
        i++;
      }
      else {
        arr[k] = R[j];
        j++;
      }
      k++;
    }
    while (i < n1) {   
      arr[k] = L[i];   
      i++;   
      k++;
    }
    while (j < n2) {   
      arr[k] = R[j];   
      j++;   
      k++;   
    }   
}   
void merge_sort(int arr[], int left, int right) {   
  if (left < right) {   
    int mid = left + (right - left) / 2;

    merge_sort(arr, left, mid);   
    merge_sort(arr, mid + 1, right); 4

    merge(arr, left, mid, right);   
}   
}

对长度为 n 的数组 arr ,挑用函数 merge_sort(a, 0, n-1) ,在排序过程中 merge 函数的递归调用次数大约是(B )。

11. 现在有 n 个人要过河,每只船最多载2人,船的承重为100kg。下列代码中,数组 weight 中保存有 n 个人 的体重(单位为kg),已经按从小到大排好序,代码输出过河所需要的船的数目,采用的思想为(B)。

int i, j;
int count = 0;
for (i = 0, j = n - 1; i < j; j--) {     
  if (weight[i] + weight[j] <= 100) {         
  i++;     
  }     
  count++;
}
printf("过河的船数:%d\n", count);

12. 关于分治算法,以下哪个说法正确 (A)?

13. 根据下述二分查找法,在排好序的数组 1,3,6,9,17,31,39,52,61,79 中查找数值 31 ,循环 while (left <= right) 执行的次数为(C)。

int binary_search(vector<int>& nums, int target) {
  int left = 0;
  int right = nums.size() - 1;

  while (left <= right) {
    int mid = left + (right - left) / 2;

    if (nums[mid] == target) {
      return mid;
    }
    else if (nums[mid] < target) {
      left = mid + 1;
    }
      else {
        right = mid - 1;
      }
  }

  return -1; // 如果找不到目标元素,返回-1
}

14. 以下关于高精度运算的说法错误的是(C).

选项 A. 105

选项 B. 840

选项 C. 210

选项 D. 420

判断题

1. 在操作系统中,需要对一组进程进行循环。每个进程被赋予一个时间片,当时间片用完时,CPU将切换到下 一个进程。这种循环操作可以通过环形链表来实现。

2. 找出自然数n 以内的所有质数,常用算法有埃拉托斯特尼(埃氏)筛法和线性筛法,其中线性筛法效率更 高。

3. 唯一分解定理表明任何一个大于1 的整数都可以唯一地分解为素数之和。

4. 贪心算法通过每一步选择局部最优解,从而一定能获得最优解。

5. 快速排序和归并排序的平均时间复杂度均为 O(n \log n),且都是稳定排序。

6. 插入排序的时间复杂度总是比快速排序低。

7. 引入分治策略往往可以提升算法效率。一方面,分治策略减少了操作数量;另一方面,分治后有利于系统的 并行优化。

8. 二分查找要求被搜索的序列是有序的,否则无法保证正确性。

9. 在C++语言中,递归的实现方式通常会占用更多的栈空间,可能导致栈溢出。

10. 对于已经定义好的标准数学函数sin(x),应用程序中的语句 y=sin(sin(x)); 是一种递归调用。