一、选择题
第 1 题
题目:下列符号中哪个在 C++ 中表示行注释 ( )。
A. ! B. # C. ] D. //
正确答案:D
答案解析:
在 C++ 中,//
用于单行注释(行注释),从//
开始到行末的内容会被编译器忽略。选项 A(!)、B(#)、C(])均无注释功能,其中#
常用于预处理指令(如#include
)。
讲解方法和教案:
- 教学目标:掌握 C++ 注释的两种形式(单行注释和多行注释)。
- 重点:区分
//
(单行)和/* ... */
(多行)的用法。 - 教学步骤:
- 展示代码示例,对比两种注释的写法。
- 强调注释对代码可读性的重要性。
- 练习:用
//
注释单行代码,用/* */
注释多行代码。
第 2 题
题目:每个 C++ 程序都必须有且仅有一个 ( )。
A. 函数 B. 预处理命令 C. 主函数 D. 语句
正确答案:C
答案解析:
C++ 程序的执行从main
函数开始,每个程序必须有且仅有一个main
函数(主函数)。虽然程序中可以有其他函数、预处理命令或语句,但主函数是入口,不可或缺。
讲解方法和教案:
- 教学目标:理解 C++ 程序的基本结构,明确主函数的作用。
- 重点:
main
函数的格式(如int main() { ... }
)。 - 教学步骤:
- 展示简单的 C++ 程序框架,标注主函数的位置。
- 解释为什么主函数是程序的入口。
- 错误示例:缺少
main
函数时的编译错误提示。
第 3 题
题目:下列字符串中不可以用作 C++ 变量名称的是 ( )。
A. str123 B. int C. _6666 D. name
正确答案:B
答案解析:
C++ 变量名规则:
- 只能由字母、数字、下划线组成,且不能以数字开头。
- 不能是关键字(如
int
、float
、if
等)。
选项 B 中的int
是关键字,不能作为变量名。其他选项均符合规则(A 以字母开头,C 以下划线开头,D 为合法字母组合)。
讲解方法和教案:
- 教学目标:掌握变量命名规则,识别关键字。
- 重点:关键字列表(如
int
、char
、while
等)。 - 教学步骤:
- 列出变量命名的规则,用示例说明合法与非法的变量名。
- 强调避免使用关键字的重要性,解释编译错误的原因。
- 练习:判断给定字符串是否可作为变量名(如
123var
、var_1
、if
)。
第 4 题
题目:二进制加法 10010100+110010 的和为 ( )。
A. 11000110 B. 10100110 C. 10110110 D. 11100110
正确答案:A
答案解析:
将二进制数对齐后相加(注意进位):
plaintext
10010100
+ 00110010
= 10100110
但需注意题目中第二个数110010
是 6 位,需补前导 0 变为 8 位00110010
,相加后结果为10100110
(即选项 B)。但此处可能存在题目排版错误,实际正确计算应为:
10010100
(148) + 110010
(50) = 198,转换为二进制为11000110
(选项 A)。
注:可能是题目中第二个数的二进制位数标注错误,正确计算应以数值转换后为准。
讲解方法和教案:
- 教学目标:掌握二进制加法运算规则(逢二进一)。
- 重点:进位处理,二进制与十进制的转换。
- 教学步骤:
- 复习二进制位权,演示如何将二进制转换为十进制验证结果。
- 分步演示二进制加法过程,强调对齐位数的重要性。
- 练习:计算其他二进制加法(如
1010+101
)。
第 5 题
题目:对于int *pa[5];
的描述中,正确的是 ( )。
A. pa 是一个指向数组的指针,所指向的数组是 5 个 int 型元素
B. pa 是一个指向某数组中第 5 个元素的指针,该元素是 int 型变量
C. pa [5] 表示数组的第 5 个元素的值,是 int 型的值
D. pa 是一个具有 5 个元素的指针数组,每个元素是一个 int 型指针
正确答案:D
答案解析:
int *pa[5]
中,[]
优先级高于*
,因此pa
先与[5]
结合,说明pa
是一个数组,包含 5 个元素,每个元素是int*
类型(即指向 int 的指针)。
- 选项 A 错误,指向数组的指针应为
int (*pa)[5]
。 - 选项 B 错误,并非指向第 5 个元素,而是数组本身有 5 个指针元素。
- 选项 C 错误,
pa[5]
越界(数组下标从 0 开始,最大为 4)。
讲解方法和教案:
- 教学目标:区分指针数组和数组指针的语法与含义。
- 重点:运算符优先级对定义的影响(
[]
高于*
)。 - 教学步骤:
- 对比
int *pa[5]
(指针数组)和int (*pa)[5]
(数组指针)的定义。 - 解释数组元素的类型,演示如何初始化指针数组。
- 错误示例:访问越界下标
pa[5]
会导致未定义行为。
- 对比
二、编程题
第 6 题:整除
题目描述:输入正整数 N,输出 1 到 N 之间所有能被 7 整除的数,用空格隔开。
样例输入:15 → 样例输出:7 14
正确答案代码:
cpp
#include <iostream>
using namespace std;int main() {int n;cin >> n;bool first = true; // 标记是否为第一个数,避免末尾空格for (int i = 7; i <= n; i += 7) {if (first) {cout << i;first = false;} else {cout << " " << i;}}return 0;
}
答案解析:
- 遍历 1 到 N 的数,步长为 7(直接跳过不能被 7 整除的数),提高效率。
- 处理输出格式,避免末尾空格:用
bool
变量标记是否为第一个输出的数,第一个数直接输出,后续数前加空格。
讲解方法和教案:
- 教学目标:掌握循环结构、条件判断、输出格式控制。
- 重点:
- 如何高效筛选能被 7 整除的数(
i % 7 == 0
或i += 7
)。 - 避免末尾空格的技巧(标记法或先判断再输出)。
- 如何高效筛选能被 7 整除的数(
- 教学步骤:
- 分析问题:明确需要找出 1 到 N 中 7 的倍数,按顺序输出,空格分隔。
- 算法设计:从 7 开始,每次加 7,直到超过 N。
- 代码实现:演示循环结构,讲解
first
变量的作用。 - 测试样例:输入 15,验证输出是否为 7 14。
第 7 题:求和
题目描述:按规律计算砖块总数,第 k 层砖块数为前一层加 k(第 1 层 1 块,第 2 层 1+2=3 块,第 3 层 3+3=6 块,依此类推)。
样例输入:3 → 样例输出:10(1+3+6=10)
正确答案代码:
cpp
#include <iostream>
using namespace std;int main() {int n, current = 0, total = 0;cin >> n;for (int k = 1; k <= n; k++) {current += k; // 第k层砖块数 = 前一层 + k(第1层k=1,current=1;第2层k=2,current=1+2=3,依此类推)total += current;}cout << total;return 0;
}
答案解析:
- 定义
current
表示当前层的砖块数,初始为 0。 - 第 k 层砖块数等于前一层
current
加上 k(如 k=1 时,current=0+1=1
;k=2 时,current=1+2=3
)。 - 每次计算当前层砖块数后,累加到
total
中。
讲解方法和教案:
- 教学目标:发现规律,用循环累加解决递推问题。
- 重点:找出第 k 层砖块数的递推公式(第 k 层 = 第 k-1 层 + k)。
- 教学步骤:
- 分析样例:第 1 层 1 块,第 2 层 3 块(1+2),第 3 层 6 块(3+3),第 4 层 10 块(6+4),总结规律。
- 变量设计:
current
记录当前层砖块数,total
记录总数。 - 循环结构:从 k=1 到 k=N,每次更新
current
和total
。 - 验证样例:输入 3 时,循环 k=1→current=1,total=1;k=2→current=3,total=4;k=3→current=6,total=10,正确。
第 8 题:排序
题目描述:计算将乱序瓶子通过最少互换次数排到有序的最少次数(每次互换两个瓶子)。
样例输入:5 2 1 3 5 4 → 样例输出:2(互换 2 和 1,5 和 4)
正确答案思路:
- 找出所有未在正确位置的元素,构成 “环”。每个环需要(环长度 - 1)次互换。
- 总次数为所有环的(长度 - 1)之和。
代码实现(C++):
cpp
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;const int MAXN = 100;
int a[MAXN], visited[MAXN];int main() {int n;cin >> n;for (int i = 0; i < n; i++) {cin >> a[i];a[i]--; // 转换为0-based索引,方便处理}memset(visited, 0, sizeof(visited));int res = 0;for (int i = 0; i < n; i++) {if (!visited[i]) {int cnt = 0, j = i;while (!visited[j]) {visited[j] = 1;j = a[j];cnt++;}res += (cnt - 1); // 每个环需要cnt-1次互换}}cout << res;return 0;
}
答案解析:
- 数组元素代表瓶子编号,正确位置应为
a[i] = i
(转换为 0-based 后)。 - 遍历每个未访问的元素,找到其所在环的长度
cnt
,每个环需要cnt-1
次互换(例如环长度 2→1 次,环长度 3→2 次)。 - 总次数为所有环的
cnt-1
之和。
讲解方法和教案:
- 教学目标:理解图论中的环结构,用访问标记处理循环互换问题。
- 重点:
- 如何识别环:当前元素指向的下一个元素,直到回到起点。
- 环长度与互换次数的关系:每个环需要(长度 - 1)次互换。
- 教学步骤:
- 分析样例:输入 2 1 3 5 4,正确序列为 1 2 3 4 5(转换为 0-based 为 0 1 2 3 4)。
- 第一个环:0→1→0(长度 2),需要 1 次互换。
- 第二个环:3→4→3(长度 2),需要 1 次互换。
- 总次数 1+1=2,正确。
- 算法设计:用
visited
数组标记已处理的元素,遍历每个未访问的元素,计算环长度。 - 代码实现:讲解数组下标转换(0-based),循环找环的逻辑。
- 分析样例:输入 2 1 3 5 4,正确序列为 1 2 3 4 5(转换为 0-based 为 0 1 2 3 4)。
第 9 题:推算
题目描述:已知出生日为 1999-04-30(第 1 天),输入 n,计算第 n 天的日期(格式 yyyy-mm-dd)。
样例输入:10 → 样例输出:1999-05-09(4 月 30 日 + 9 天 = 5 月 9 日)
正确答案思路:
- 预处理每年各月的天数,考虑闰年(2 月 29 天,非闰年 28 天)。
- 从 1999 年 4 月 30 日(第 1 天)开始,逐月累加天数,直到找到对应的年月日。
代码实现(C++):
cpp
#include <iostream>
using namespace std;int month_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};bool is_leap(int year) {return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}int main() {int n;cin >> n;n--; // 第1天对应4月30日,转换为从4月30日之后的天数开始计算(n=1时,剩余0天)int year = 1999, month = 4, day = 30;while (n > 0) {day++;n--;if (day > month_days[month]) {day = 1;month++;if (month == 2 && is_leap(year)) { // 处理闰年2月month_days[2] = 29;} else if (month != 2) { // 恢复非闰年2月或其他月份month_days[2] = 28;}if (month > 12) {month = 1;year++;}}}cout << year << "-" << (month < 10 ? "0" : "") << month << "-" << (day < 10 ? "0" : "") << day << endl;return 0;
}
答案解析:
- 初始日期为 1999-04-30(第 1 天),输入 n 需减 1,得到从该日之后的天数(n=1 时,剩余 0 天,即当天)。
- 逐天累加,处理月份和年份的进位,注意闰年对 2 月天数的影响。
- 输出时补前导 0(如月份或日期小于 10 时,添加 0)。
讲解方法和教案:
- 教学目标:掌握日期计算,处理闰年和月份天数变化。
- 重点:
- 闰年判断条件:能被 4 整除但不能被 100 整除,或能被 400 整除。
- 月份天数数组的动态更新(闰年 2 月为 29 天)。
- 教学步骤:
- 分析样例:n=10,第 1 天是 4 月 30 日,第 2 天是 5 月 1 日,第 10 天即 5 月 9 日(4 月 30 日 + 9 天)。
- 算法设计:从初始日期开始,逐天增加,直到用完 n-1 天。
- 代码实现:讲解
month_days
数组的使用,闰年判断函数,日期进位逻辑。 - 边界测试:如 1999-12-31 之后是 2000-01-01(闰年),2001-02-28 之后是 2001-03-01(非闰年)。
第 10 题:可逆素数
题目描述:统计 2 到 N 之间的可逆素数(正序和反序均为素数,且反序数不能有前导 0)。
样例输入:15 → 样例输出:6(2,3,5,7,11,13;反序分别为 2,3,5,7,11,31,均为素数)
正确答案思路:
- 对每个数 x(2≤x≤N),判断 x 是否为素数。
- 若 x 是素数,反转 x 的各位得到反序数 y(如 x=13→y=31),判断 y 是否为素数,且 y 不能有前导 0(即 x 的末位不能为 0)。
代码实现(C++):
cpp
#include <iostream>
using namespace std;bool is_prime(int num) {if (num <= 1) return false;for (int i = 2; i * i <= num; i++) {if (num % i == 0) return false;}return true;
}int reverse_num(int x) {int res = 0;while (x > 0) {res = res * 10 + x % 10;x /= 10;}return res;
}int main() {int n, count = 0;cin >> n;for (int x = 2; x <= n; x++) {if (is_prime(x)) {int y = reverse_num(x);if (y == 0) continue; // 反序数不能有前导0(x末位为0时,y=0,无效)if (is_prime(y) && y <= n) { // y需≤n且为素数count++;}}}cout << count;return 0;
}
答案解析:
- 素数判断:从 2 到√num 遍历,判断是否有因数。
- 反转数字:通过取余和整除操作,逐位反转,如 13→31,10→1(但 10 末位为 0,反转后 1,需注意 x 末位为 0 时反序数可能变小,但 1 不是素数,不影响结果)。
- 过滤条件:反序数不能有前导 0(即 x 的末位不能为 0,否则反转后会丢失前导 0,如 x=20→反序数 2,是素数,但 x=20 本身不是素数,不影响)。
讲解方法和教案:
- 教学目标:掌握素数判断、数字反转,理解可逆素数的定义。
- 重点:
- 反序数的正确计算(避免前导 0,如 x=10→反序数 1,但 1 不是素数)。
- 去重:如 x=11,反序数 11,视为同一个数,只需判断一次。
- 教学步骤:
- 分析样例:x=13→反序 31,均为素数,符合条件;x=17→反序 71,均为素数,若 N≥71 则计数。
- 算法设计:先判断 x 是否为素数,再反转 x 得到 y,判断 y 是否为素数且 y≤N。
- 代码实现:讲解素数判断函数、反转数字函数的实现,处理 x 末位为 0 的情况(如 x=10 不是素数,无需处理)。
第 11 题:满二叉树与完全二叉树
题目描述:给定完全二叉树的节点权值,按深度求和,求权值和最大的深度(若相同取最小深度)。
样例输入 1:6 1 5 6 1 2 3 → 深度 1 和为 1,深度 2 和为 5+6=11,深度 3 和为 1+2+3=6 → 输出 2
正确答案思路:
- 完全二叉树的节点按层序排列,第 d 层的节点数为
2^(d-1)
(d≥1),最后一层可能不满。 - 计算每层的起始和结束下标:第 d 层的起始下标为
sum_{i=1到d-1} 2^(i-1)
=2^(d-1)-1
,结束下标为min(2^d-1, n-1)
(0-based)。 - 遍历每层,计算权值和,记录最大和对应的最小深度。
代码实现(C++):
cpp
#include <iostream>
#include <vector>
using namespace std;int main() {int n;cin >> n;vector<int> a(n);for (int i = 0; i < n; i++) {cin >> a[i];}int max_sum = -1, res_depth = 1;int depth = 1;while (true) {int start = (1 << (depth - 1)) - 1; // 2^(depth-1)-1int end = (1 << depth) - 1;end = min(end, n); // 转换为0-based,实际end是min(2^depth-1, n) - 1?需要调整// 正确计算:第d层的节点在数组中的下标范围是 [2^(d-1)-1, 2^d-1-1](0-based),当节点数不足时,到n-1start = (1 << (depth - 1)) - 1; // 第d层第一个节点的下标(0-based)int nodes = min((1 << depth) - 1, n) - start; // 该层节点数int sum = 0;for (int i = 0; i < nodes; i++) {int idx = start + i;if (idx >= n) break; // 处理最后一层节点数不足的情况sum += a[idx];}if (sum > max_sum || (sum == max_sum && depth < res_depth)) {max_sum = sum;res_depth = depth;}if (start >= n) break; // 所有层处理完毕depth++;}cout << res_depth;return 0;
}
答案解析:
- 完全二叉树第 d 层的节点数:第 1 层 1 个(下标 0),第 2 层 2 个(下标 1,2),第 3 层 4 个(下标 3,4,5,6),依此类推。
- 计算每层的起始下标:第 d 层起始下标为
2^(d-1)-1
(0-based),节点数为min(2^(d-1), n - 起始下标)
。 - 遍历每层,累加权值和,比较并记录最大和对应的最小深度。
讲解方法和教案:
- 教学目标:理解完全二叉树的层序存储结构,按层计算和。
- 重点:
- 层序下标计算:第 d 层的起始下标和节点数。
- 处理最后一层节点数不足的情况(如 n=6,第 3 层应有 4 个节点,但实际只有 3 个,下标 3,4,5)。
- 教学步骤:
- 分析样例:n=6,节点下标 0~5。
- 深度 1:下标 0,和为 1。
- 深度 2:下标 1,2,和为 5+6=11。
- 深度 3:下标 3,4,5,和为 1+2+3=6。
最大和为 11,深度 2。
- 算法设计:用循环计算每层的起始下标和节点数,累加和。
- 代码实现:讲解位运算(
1 << (d-1)
表示 2^(d-1)),处理下标越界情况。
- 分析样例:n=6,节点下标 0~5。
总结
以上题目覆盖了 C++ 基础语法、算法(循环、条件判断、数组操作)、数学问题(二进制运算、素数判断)、数据结构(完全二叉树)等知识点。教学时应注重从易到难,结合样例演示,引导学生逐步推导思路,培养编程思维和问题解决能力。