一、選擇題
第 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++ 基礎語法、算法(循環、條件判斷、數組操作)、數學問題(二進制運算、素數判斷)、數據結構(完全二叉樹)等知識點。教學時應注重從易到難,結合樣例演示,引導學生逐步推導思路,培養編程思維和問題解決能力。