GESP认证C++编程真题解析 | 202406 六级
附上汇总帖:GESP认证C++编程真题解析 | 汇总
单选题
第1题
面向对象的编程思想主要包括( )原则。
A. 贪心、动态规划、回溯
B. 并发、并行、异步
C. 递归、循环、分治
D. 封装、继承、多态
【答案】:D
【解析】
A选项属于算法范畴。B选项涉及计算机系统和操作系统领域,不是面向对象编程的核心原则。C选项也属于语法和算法范畴。D选项是面向对象编程的三大基本原则。
第2题
运行下列代码,屏幕上输出( )。
#include <iostream>
using namespace std;
class my_class {
public:
static int count;
my_class() {
count++;
}
~my_class() {
count--;
}
static void print_count() {
cout << count << " ";
}
};
int my_class::count = 0;
int main() {
my_class obj1;
my_class::print_count();
my_class obj2;
obj2.print_count();
my_class obj3;
obj3.print_count();
return 0;
}
A. 1 1 1
B. 1 2 3
C. 1 1 2
D. 1 2 2
【答案】:B
【解析】
程序的主要逻辑:
- my_class类中有一个静态成员变量count,用于计数。
- 每创建一个my_class对象时,构造函数会将count加1;每销毁一个对象时,析构函数会将count减1。
- 静态方法print_count()用于输出当前的count值。
执行流程及输出分析
- 在main函数开始前,my_class::count被初始化为0。
- 创建第一个对象obj1:count变为1。
- 调用print_count() :输出1。
- 创建第二个对象obj2:count变为2。
- 调用print_count() :输出2。
- 创建第三个对象obj3:count变为3。
- 调用print_count() :输出3。
因此,这段代码的输出结果是:123。
第3题
运行下列代码,屏幕上输出( )。
#include <iostream>
using namespace std;
class shape {
protected:
int width, height;
public:
shape (int a = 0, int b = 0) {
width = a;
height = b;
}
virtual int area() {
cout << "parent class area: " << endl;
return 0;
}
};
class rectangle: public shape {
public:
rectangle(int a = 0, int b = 0) : shape(a, b) { }
int area () {
cout << "rectangle area: ";
return (width * height);
}
};
class triangle: public shape {
public:
triangle(int a = 0, int b = 0) : shape(a, b) { }
int area () {
cout << "triangle area: ";
return (width * height / 2);
}
};
int main() {
shape *pshape;
rectangle rec(10, 7);
triangle tri(10, 5);
pshape = &rec;
pshape->area();
pshape = &tri;
pshape->area();
return 0;
}
A. rectangle area: triangle area:
B. parent class area: parent class area:
C. 运行时报错
D. 编译时报错
【答案】:A
【解析】
执行流程及输出分析:
-
定义并初始化对象
- 定义了一个指向shape类型的指针pshape。
- 创建了两个具体的形状对象:矩形rec(10, 7)和三角形tri(10, 5)。
-
第一次调用area()方法
-
将pshape指向rec对象,并调用pshape->area()。
-
因为area()是虚函数,所以会调用rectangle类中的area()方法。
水电费水电费
cout << "rectangle area: "; return (width * height); // 返回70,但返回值未被使用 -
输出:reactangle area:。
-
-
第二次调用area()方法
-
将pshape指向tri对象,并调用pshape->area()。
-
同样因为area()是虚函数,会调用triangle类中的area()方法。
cout << "triangle area: "; return (width * height / 2); // 返回25,但返回值未被使用 -
输出:triangle area:。
-
综上所述,程序的输出结果是:rectangle area: triangle area:
第4题
向一个栈顶为hs的链式栈中插入一个指针为s的结点时,应执行( )。
A. hs->next = s;
B. s->next = hs, hs = s;
C. s->next = hs->next; hs->next = s;
D. s->next = hs; hs = hs->next;
【答案】:B
【解析】
在链式栈中,新的元素总是插入到链表的头部,也就是说,新节点将成为第一个节点,而之前的第一个节点将成为第二个节点。
A. hs->next = s;
这个选项仅仅是把hs的下一个节点设为s,并没有更新hs本身,s也没有成为新的栈顶,这样会导致链表结构不正确。
B. s->next = hs, hs = s;
该选项首先将s的next指向当前的头节点hs,然后再将hs更新为s。这样做实际上是在链表头部插入了新的节点s,符合要求。
C. s->next = hs->next; hs->next = s;
这个选项让新节点s插入到hs后面的第二个位置,不符合链式栈的特性。
D. s->next = hs; hs = hs->next;
这个选项让新节点s的next指向当前的hs,但随后又把hs更新为hs->next,所以最后hs并不是指向新节点s,逻辑上是不正确的。
第5题
在栈数据结构中,元素的添加和删除是按照什么原则进行的?
A. 先进先出
B. 先进后出
C. 最小值先出
D. 随机顺序
【答案】B
【解析】
栈是一种“先进后出”(或“后进先出)的数据结构,最新加入的元素会最先被移除
第6题
要实现将一个输入的十进制正整数转化为二进制表示,下面横线上应填入的代码为( )。
#include <iostream>
using namespace std;
stack<int> ten2bin(int n) {
stack<int> st;
int r, m;
r = n % 2;
m = n / 2;
st.push(r);
while (m != 1) {
r = m % 2;
st.push(r);
m = m / 2;
}
st.push(m);
return st;
}
int main() {
int n;
cin >> n;
stack<int> bin;
bin = ten2bin(n);
while (!bin.empty()) {
____ // 在此处填入代码
}
return 0;
}
A. cout << bin.top(); bin.top();
B. bin.pop(); cout << bin.top();
C. cout << bin.back(); bin.pop();
D. cout << bin.front(); bin.pop();
【答案】:A
【解析】
主函数读取输入的整数n,调用ten2bin函数将其转换为二进制,并将结果存储在bin栈中。然后,通过循环遍历该栈,输出其中的元素。
填空部分分析:
为了正确地输出二进制表示,需要从栈顶依次弹出元素并打印,因为栈是LIFO结构,而我们需要按顺序输出二进制位。
A. cout << bin.top(); bin.top();
这是正确的选择,因为它首先获取栈顶元素并输出,然后移除栈顶元素,从而实现正确的二进制输出。
B. bin.pop(); cout << bin.top();
这是错误的,因为它先移除了栈顶元素,再试图访问栈顶,这会使得第1位的值没有输出,从而导致结果错误。
C. cout << bin.back(); bin.pop();
这是错误的,因为stack容器没有back()方法。
D. cout << bin.front(); bin.pop();
这是错误的,因为stack容器没有front()方法。
因此,正确的代码应该是:A.cout << bin.top(); bin.top();
第7题
下面定义了一个循环队列的类,请补全判断队列是否满的函数,横向上应填写( )
#include <iostream>
using namespace std;
class circular_queue {
private:
int *arr; // 数组用于存储队列元素
int capacity; // 队列容量
int front; // 队头指针
int rear; // 队尾指针
public:
circular_queue(int size) {
capacity = size + 1; // 为了避免队列满时与队列空时指针相等的情况,多预留一个空间
arr = new int[capacity];
front = 0;
rear = 0;
}
~circular_queue() {
delete[] arr;
}
bool is_empty() {
return front == rear;
}
bool is_full() {
____ // 在此处填入代码
}
void en_queue(int data) {
if (is_full()) {
cout << "队列已满,无法入队!" << endl;
return -1;
}
arr[rear] = data;
rear = (rear + 1) % capacity;
return 1;
}
int de_queue() {
if (is_empty()) {
cout << "队列为空,无法出队!" << endl;
return -1; // 出队失败,返回一个特殊值
}
int data = arr[front];
front = (front + 1) % capacity;
return data;
}
};
A. return (rear + 1) % capacity == front;
B. return rear % capacity == front;
C. return rear == front;
D. return (rear + 1) == front;
【答案】:A
【解析】
为了区分队列满和队列空状态,我们使用额外的一个空间。当(rear+1) % capacity == front时,说明队列已经满了。
第8题
对"classmycls"使用哈夫曼(Huffman)编码,最少需要( )比特。
A. 10
B. 20
C. 25
D. 30
【答案】:C
【解析】
字符串“classmycls”的字符频率:
- c:2次
- l:2次
- a:1次
- s:3次
- m:1次
- y:1次
构建哈夫曼树(根据字符的频率,从小到大排序,并依次合并节点)并生成编码(从根节点开始,左边路径标记为0,右边路径标记为1)
计算总比特数:
根据每个字符的频率乘以其编码长度,然后求和得到总比特数。
- c:2 * 2 = 4 bits
- l:2 * 2 = 4 bits
- a:1 * 4 = 4 bits
- s:3 * 2 = 6 bits
- m:1 * 4 = 4 bits
- y:1 * 3 = 3 bits
总比特数=4+4+4+6+4+3=25bits。因此,答案应该是C。
第9题
二叉树的( )第一个访问的节点是根节点。
A. 先序遍历
B. 中序遍历
C. 后序遍历
D. 以上都是
【答案】A
【解析】
先序遍历:按照“根-左-右”的顺序进行遍历。
第10题
一棵5层的满二叉树中节点数为( )。
A. 31
B. 32
C. 33
D. 16
【答案】:A
【解析】
满二叉树:在满二叉树中,所有非叶子节点都有两个子节点,并且所有叶子节点都在同一层。满二叉树的节点总数可以用公式来表示:。其中(N)是节点总数,(h)是树的高度(层数)。
对于一棵5层的满二叉树来说:节点总数=-1=31。
因此,正确答案是A。
第11题
在求解最优化问题时,动态规划常常涉及到两个重要性质,即最优子结构和( )。
A. 重叠子问题
B. 分治法
C. 贪心策略
D. 回溯算法
【答案】A
【解析】
动态规划的基本原理和它所依赖的两个关键性质:
- 重叠子问题:这是指将一个大问题分解成多个小问题,这些小问题会被多次重复计算。在动态规划中,通过存储这些小问题的结果,可以避免重复计算,从而提高效率。
- 最优子结构:这是指一个问题的最优解可以通过其子问题的最优解来构建,这意味着解决了子问题的最优解后,可以组合成原问题的最优解。
因此,正确答案是A。
第12题
青蛙每次能跳1或2步,下面代码计算青蛙跳到第n步台阶有多少种不同跳法。则下列说法,错误的是( )。
int jump_recur(int n) {
if (n==1) return 1;
if (n==2) return 2;
return jump_recur(n-1) + jump_recur(n-2);
}
int jump_dp(int n) {
vector<int> dp(n+1); // 创建一个动态规划数组,用于保存已计算的值
// 初始化前两个数
dp[1] = 1;
dp[2] = 2;
// 从第三个数开始计算斐波那契数列
for (int i=3; i<=n; ++i) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
A. 函数jump_recur()采用递归方式。
B. 函数jump_dp()采用动态规划方法。
C. 当n较大时,函数jump_recur()存在大量重复计算,执行效率低。
D. 函数jump_recur()代码量小,执行效率高。
【答案】:D
【解析】
A. 函数jump_recur()采用递归方式。
从代码中可以看到,jump_recur函数通过调用自身来解决子问题,这正是递归的定义。因此这个选项是正确的
B. 函数jump_dp()采用动态规划方法
jump_dp函数创建了一个数组dp来存储已经计算过的结果,并从底向上地填充该数组。这正是动态规划的典型实现方法。因此这个选项也是正确的
C. 当n较大时,函数jump_recur()存在大量重复计算,执行效率低。
由于jump_recur包每次都要重新计算之前的结果,当n较大时,会导致大量的重复计算,从而使得效率很低。因此这个选项也是正确的。
D. 函数jump_recur()代码量小,执行效率高。
虽然jump_recur的代码量确实较少,但它的执行效率并不高,尤其是在n较大的情况下会有大量的重复计算。因此这个选项是错误的。
综上所述,正确答案是D。
第13题
阅读以下二叉树的广度优先搜索代码:
#include <iostream>
#include <queue>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 宽度优先搜索(BFS)迭代实现
TreeNode* bfs(TreeNode* root, int a) {
if (root==nullptr) return nullptr;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (node->val == a)
return node;
cout << node->val << " "; // 先访问当前节点
if (node->left) q.push(node->left); // 将左子节点入队
if (node->right) q.push(node->right); // 将右子节点入队
}
return nullptr;
}
使用以上算法,在以下这棵树搜索数值20时,可能的输出是( )。

A. 5 2 -4 3 17 9
B. -4 2 3 5 9 17
C. 5 2 17 -4 3 9
D. 以上都不对
【答案】:C
【解析】
bfs函数实际上对于二叉树进行层次遍历,在遍历的过程中来找值(val)为20的结点,由于没有该结点,所以会把整棵树遍历结束之后就返回nullptr。
因此,最终的输出就是层次遍历的结果:5 2 17 -4 3 9。
第14题
同上题中的二叉树,阅读以下二叉树的深度优先搜索代码:
#include <iostream>
#include <stack>
using namespace std;
// 非递归深度优先搜索(DFS)
TreeNode* dfs(TreeNode* root, int a) {
if (root == nullptr) return nullptr;
stack<TreeNode*> stk;
stk.push(root);
while (!stk.empty()) {
TreeNode* node = stk.top();
stk.pop();
if (node->val == a)
return node;
cout << node->val << " "; // 访问当前节点
if (node->right) stk.push(node->right); // 先压入右子节点
if (node->left) stk.push(node->left); // 再压入左子节点
}
return nullptr;
}
使用以上算法,在二叉树搜索数值20时,可能的输出是( )。
A. 5 2 -4 3 17 9
B. -4 2 3 5 9 17
C. 5 2 17 -4 3 9
D. 以上都不对
【答案】A
【解析】
dfs函数实际上对于二叉树进行先序遍历,在遍历的过程中来找值(ual)为20的结点,由于没有该结点,所以会把整棵树遍历结束之后就返回null ptr。
因此,最终的输出就是先序遍历的结果:5 2 -4 3 17 9。
第15题
在上题的树中搜索数值3时,采用深度优先搜索一共比较的节点数为( )。
A. 2
B. 3
C. 4
D. 5
【答案】C
【解析】
深度优先搜索过程:
- 从根节点5开始,将其加入栈。
- 弹出栈顶元素5,检查是否等于目标值3。不是,于是将5的右子节点17和左子节点2压入栈。
- 弹出栈顶元素2,检查是否等于目标值3。不是,于是将2的右子节点3和左子节点-4压入栈。
- 弹出栈顶元素-4,检查是否等于目标值3。不是,继续。
- 弹出栈顶元素3,检查是否等于目标值3。是,找到目标节点。
根据上述步骤,共访问了四个节点:5,2,-4,3,需要比较的节点数是4个。所以正确答案是C。
判断题
第1题
哈夫曼编码本质上是一种贪心策略。
A. 正确
B. 错误
【答案】:A
【解析】
哈夫曼编码(Huffman coding)是一种用于数据压缩的算法,确实基于贪心策略来构建最优前缀码。
第2题
创建一个对象时,会自动调用该对象所属类的构造函数。如果没有定义构造函数,编译器会自动生成一个默认的构造函数。
A. 正确
B. 错误
【答案】:A
【解析】
在C++中,如果没有定义任何构造函数,编译器会提供一个隐式的默认构造函数。
第3题
定义一个类时,必须手动定义一个析构函数,用于释放对象所占用的资源。
A. 正确
B. 错误
【答案】:B
【解析】
在C++中,如果不定义析构函数,编译器会生成一个默认的析构函数,但如果类管理动态内存或其他资源,通常需要自定义析构函数以确保资源被正确释放。
第4题
C++中类内部可以嵌套定义类。
A. 正确
B. 错误
【答案】:A
【解析】
在C++中,可以在一个类的内部定义另一个类,这称为嵌套类。
第5题
000, 001, 011, 010, 110, 111, 101, 100是一组格雷码。
A. 正确
B. 错误
【答案】:A
【解析】
格雷码是一种二进制数系,其中相邻两个数只有一位不同。这组数字确实符合格雷码的定义。
第6题
n个节点的双向循环链表,在其中查找某个节点的平均时间复杂度是O(logn)。
A. 正确
B. 错误
【答案】:B
【解析】
对于链表结构,无论是单向还是双向,其查找操作的平均时间复杂度都是O(n)而不是O(logn)。
第7题
完全二叉树可以用数组存储数据。
A. 正确
B. 错误
【答案】:A
【解析】
完全二叉树可以非常方便地用数组来存储数据。对于一个节点在数组中的位置(i)(假设从1开始计数),其子节点和父节点的位置可以通过以下公式计算:
- 左孩子节点的位置:2i
- 右孩子节点的位置:2i+1
- 父节点的位置:
这种方式利用了完全二叉树的性质,即除了最后一层外,每一层都是满的,并且最后一层的所有节点尽可能靠左排列。
第8题
在C++中,静态成员函数只能访问静态成员变量。
A. 正确
B. 错误
【答案】:A
【解析】
静态成员函数不能访问非静态成员变量,因为它们属于类本身,而不是某个具体的对象实例。
第9题
在深度优先搜索中,通常使用队列来辅助实现。
A. 正确
B. 错误
【答案】:A
【解析】
深度优先搜索(DFS)通常使用栈来实现,而广度优先搜索(BFS)才使用队列。
第10题
对0-1背包问题,贪心算法一定能获得最优解。
A. 正确
B. 错误
【答案】:A
【解析】
0-1背包问题是NP完全问题,贪心算法不能保证求得最优解,通常需要使用动态规划或搜索等方法。
浙公网安备 33010602011771号