调整课次结构:前9节重新排序,新建第06课一维数组,后3节不变
This commit is contained in:
687
第05课-自定义函数/编程题-教师版.md
Normal file
687
第05课-自定义函数/编程题-教师版.md
Normal file
@@ -0,0 +1,687 @@
|
||||
# 第2课编程题(教师版)
|
||||
|
||||
## 本课知识点覆盖表
|
||||
|
||||
| 核心知识点 | GESP等级 | 对应课堂题 |
|
||||
|---|---|---|
|
||||
| 函数声明、定义与调用 | 二级必考 | 课堂1 |
|
||||
| 形参与实参、值传递、返回值、提前 `return` | 二级必考 | 课堂2 |
|
||||
| `void` 函数与函数重载 | 二级 | 课堂3 |
|
||||
| 局部变量、全局变量与作用域 | 二级必考 | 课堂4 |
|
||||
|
||||
> 难度均为本课内部相对难度,参考程序采用 C++17。
|
||||
|
||||
## 一、课堂练习(4题)
|
||||
|
||||
### 课堂1:三个数的最大公约数【适中】
|
||||
|
||||
**题目描述:** 编写函数 `gcd(a,b)`,使用辗转相除法求两个正整数的最大公约数。在 `main` 前写函数声明、`main` 后写函数定义,连续调用两次求三个数的最大公约数。
|
||||
|
||||
**输入格式:** 输入三个正整数。
|
||||
|
||||
**输出格式:** 三个数的最大公约数。
|
||||
|
||||
**数据范围:** `1≤a,b,c≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
12 18 30
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
6
|
||||
```
|
||||
|
||||
**解题思路:** 先求 `gcd(a,b)`,再把结果与 `c` 求最大公约数,体会函数声明、定义和多次调用。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int gcd(int a, int b);
|
||||
|
||||
int main() {
|
||||
int a, b, c;
|
||||
cin >> a >> b >> c;
|
||||
cout << gcd(gcd(a, b), c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcd(int a, int b) {
|
||||
while (b != 0) {
|
||||
int r = a % b;
|
||||
a = b;
|
||||
b = r;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 函数声明必须与定义的返回类型、函数名和参数列表一致。
|
||||
|
||||
### 课堂2:统计区间内的素数【适中】
|
||||
|
||||
**题目描述:** 编写有参数、有返回值的函数 `isPrime(n)`。输入 `L` 和 `R`,输出闭区间 `[L,R]` 中素数的个数。
|
||||
|
||||
**输入格式:** 输入区间的左端点和右端点。
|
||||
|
||||
**输出格式:** 素数个数。
|
||||
|
||||
**数据范围:** `1≤L≤R≤10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 20
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
4
|
||||
```
|
||||
|
||||
**解题思路:** 每个实参传入函数后复制给形参 `n`;找到因数时提前返回 `false`,全部检查后返回 `true`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool isPrime(int n) {
|
||||
if (n < 2) return false;
|
||||
for (int i = 2; i * i <= n; i++) {
|
||||
if (n % i == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int L, R, count = 0;
|
||||
cin >> L >> R;
|
||||
for (int x = L; x <= R; x++) {
|
||||
if (isPrime(x)) count++;
|
||||
}
|
||||
cout << count;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 1 不是素数;普通值传递不会修改主函数中的实参。
|
||||
|
||||
### 课堂3:统一格式输出【适中】
|
||||
|
||||
**题目描述:** 重载函数 `printLine`:一个版本接收一个整数并输出由该整数重复 5 次组成的一行;另一个版本接收一个字符和次数,输出指定长度的一行。两个函数都没有返回值。
|
||||
|
||||
**输入格式:** 依次输入一个整数、一个字符和字符的重复次数。
|
||||
|
||||
**输出格式:** 第一行输出 5 个 `x`;第二行输出 `n` 个字符 `c`。
|
||||
|
||||
**数据范围:** `0≤x≤9`,`1≤n≤50`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
7 * 4
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
77777
|
||||
****
|
||||
```
|
||||
|
||||
**解题思路:** 两个函数同名但参数列表不同,构成函数重载;只负责输出,因此返回类型为 `void`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void printLine(int x) {
|
||||
for (int i = 0; i < 5; i++) cout << x;
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
void printLine(char c, int n) {
|
||||
for (int i = 0; i < n; i++) cout << c;
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
int x, n;
|
||||
char c;
|
||||
cin >> x >> c >> n;
|
||||
printLine(x);
|
||||
printLine(c, n);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 重载依据参数数量或类型区分,不能只靠返回类型区分。
|
||||
|
||||
### 课堂4:全班累计加分【适中】
|
||||
|
||||
**题目描述:** 全局变量 `total` 表示全班累计加分。编写 `addScore(x)` 修改它;函数内部再定义同名局部变量 `total`,演示局部变量优先。每次调用后输出全局累计值。
|
||||
|
||||
**输入格式:** 第一行输入加分次数;第二行输入每次的加分值。
|
||||
|
||||
**输出格式:** 输出每次加分后的全局累计值。
|
||||
|
||||
**数据范围:** `1≤n≤20`,每次加分 `1~10`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
3
|
||||
2 5 1
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
2 7 8
|
||||
```
|
||||
|
||||
**解题思路:** 用 `::total` 指明全局变量;局部变量仅在函数的大括号内有效。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int total = 0;
|
||||
|
||||
void addScore(int x) {
|
||||
int total = x;
|
||||
::total += total;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n, x;
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> x;
|
||||
addScore(x);
|
||||
if (i) cout << " ";
|
||||
cout << total;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 局部变量会遮住同名全局变量;实际编程应尽量避免故意重名,本题只用于理解作用域。
|
||||
|
||||
## 二、课后作业(3题)
|
||||
|
||||
### 课后1:求长方形面积【简单】
|
||||
|
||||
**题目描述:** 编写函数 `area(a,b)` 返回长方形面积。
|
||||
|
||||
**输入格式:** 输入两个正整数。
|
||||
|
||||
**输出格式:** 长方形面积。
|
||||
|
||||
**数据范围:** `1≤a,b≤10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
4 6
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
24
|
||||
```
|
||||
|
||||
**解题思路:** 函数接收两个形参,返回它们的乘积。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int area(int a, int b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int a, b;
|
||||
cin >> a >> b;
|
||||
cout << area(a, b);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 有返回值的函数不能漏写 `return`。
|
||||
|
||||
### 课后2:判断偶数【简单】
|
||||
|
||||
**题目描述:** 编写布尔函数 `isEven(n)`,偶数返回 `true`,奇数返回 `false`。主函数据此输出 `YES` 或 `NO`。
|
||||
|
||||
**输入格式:** 输入一个整数。
|
||||
|
||||
**输出格式:** `YES` 或 `NO`。
|
||||
|
||||
**数据范围:** `-10^9≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
18
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
YES
|
||||
```
|
||||
|
||||
**解题思路:** 判断 `n%2==0` 并直接返回结果。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool isEven(int n) {
|
||||
return n % 2 == 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
cout << (isEven(n) ? "YES" : "NO");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 判断相等使用 `==`,不是赋值符号 `=`。
|
||||
|
||||
### 课后3:打印分隔线【简单】
|
||||
|
||||
**题目描述:** 编写无返回值函数 `printLine(n)`,输出 `n` 个减号。
|
||||
|
||||
**输入格式:** 输入一个整数。
|
||||
|
||||
**输出格式:** 一行 `n` 个 `-`。
|
||||
|
||||
**数据范围:** `1≤n≤100`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
-----
|
||||
```
|
||||
|
||||
**解题思路:** 输出操作封装进 `void` 函数。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void printLine(int n) {
|
||||
for (int i = 0; i < n; i++) cout << "-";
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
printLine(n);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** `void` 函数不能把调用结果赋给变量。
|
||||
|
||||
## 三、扩展练习(7题)
|
||||
|
||||
### 扩展1:绝对值函数【基础综合】
|
||||
|
||||
**题目描述:** 不使用标准库 `abs`,编写函数 `myAbs(n)` 返回整数的绝对值。
|
||||
|
||||
**输入格式:** 输入一个整数。
|
||||
|
||||
**输出格式:** `n` 的绝对值。
|
||||
|
||||
**数据范围:** `-10^9≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
-23
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
23
|
||||
```
|
||||
|
||||
**解题思路:** 负数返回 `-n`,否则返回 `n`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int myAbs(int n) {
|
||||
if (n < 0) return -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
cout << myAbs(n);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 每条可能的执行路线都应有返回值。
|
||||
|
||||
### 扩展2:数字各位和【基础综合】
|
||||
|
||||
**题目描述:** 编写函数 `digitSum(n)`,返回正整数各位数字之和。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 各位数字之和。
|
||||
|
||||
**数据范围:** `1≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5026
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
13
|
||||
```
|
||||
|
||||
**解题思路:** 在函数内循环取个位并累加。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int digitSum(int n) {
|
||||
int sum = 0;
|
||||
while (n > 0) {
|
||||
sum += n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
cout << digitSum(n);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 函数内修改形参 `n` 不会改变主函数中的实参。
|
||||
|
||||
### 扩展3:最小公倍数【中等】
|
||||
|
||||
**题目描述:** 编写 `gcd(a,b)` 和 `lcm(a,b)` 两个函数,输出两数的最小公倍数。
|
||||
|
||||
**输入格式:** 输入两个正整数。
|
||||
|
||||
**输出格式:** 最小公倍数。
|
||||
|
||||
**数据范围:** `1≤a,b≤10^6`,答案不超过 `10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
12 18
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
36
|
||||
```
|
||||
|
||||
**解题思路:** 先求最大公约数,再利用 `lcm=a/gcd*b`,体现函数之间相互调用。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int gcd(int a, int b) {
|
||||
while (b != 0) {
|
||||
int r = a % b;
|
||||
a = b;
|
||||
b = r;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
long long lcm(int a, int b) {
|
||||
return 1LL * a / gcd(a, b) * b;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int a, b;
|
||||
cin >> a >> b;
|
||||
cout << lcm(a, b);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 先除后乘并使用 `long long`,可降低中间结果溢出的风险。
|
||||
|
||||
### 扩展4:重载求面积【中等】
|
||||
|
||||
**题目描述:** 重载函数 `area`:接收一个整数时返回正方形面积;接收两个整数时返回长方形面积。输入类型编号及边长后输出面积。
|
||||
|
||||
**输入格式:** 先输入图形类型;类型为 1 时再输入一个边长,类型为 2 时再输入长和宽。
|
||||
|
||||
**输出格式:** 图形面积。
|
||||
|
||||
**数据范围:** 边长为 `1~10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
2 4 7
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
28
|
||||
```
|
||||
|
||||
**解题思路:** 用不同参数个数区分两个同名函数。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int area(int side) {
|
||||
return side * side;
|
||||
}
|
||||
|
||||
int area(int length, int width) {
|
||||
return length * width;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int type, a, b;
|
||||
cin >> type >> a;
|
||||
if (type == 1) cout << area(a);
|
||||
else {
|
||||
cin >> b;
|
||||
cout << area(a, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 两个重载版本不能拥有完全相同的参数列表。
|
||||
|
||||
### 扩展5:回文数函数【中等】
|
||||
|
||||
**题目描述:** 编写函数 `isPalindrome(n)` 判断正整数是否为回文数,输出 `YES` 或 `NO`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** `YES` 或 `NO`。
|
||||
|
||||
**数据范围:** `1≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
12321
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
YES
|
||||
```
|
||||
|
||||
**解题思路:** 在函数中备份原数并构造反转数,最后比较。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool isPalindrome(int n) {
|
||||
int original = n;
|
||||
int reversed = 0;
|
||||
while (n > 0) {
|
||||
reversed = reversed * 10 + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
return reversed == original;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
cout << (isPalindrome(n) ? "YES" : "NO");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 必须备份原数;形参被拆完后会变成 0。
|
||||
|
||||
### 扩展6:连续素数对【略难】
|
||||
|
||||
**题目描述:** 两个相差 2 的素数称为孪生素数。编写 `isPrime`,输出 `[2,n]` 中所有孪生素数对,每对占一行;若没有,输出 `NONE`。
|
||||
|
||||
**输入格式:** 输入一个整数。
|
||||
|
||||
**输出格式:** 所有满足条件的 `p p+2`。
|
||||
|
||||
**数据范围:** `2≤n≤100000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
15
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
3 5
|
||||
5 7
|
||||
11 13
|
||||
```
|
||||
|
||||
**解题思路:** 枚举较小的数 `p`,同时调用两次 `isPrime`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool isPrime(int n) {
|
||||
if (n < 2) return false;
|
||||
for (int i = 2; i * i <= n; i++) {
|
||||
if (n % i == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
bool found = false;
|
||||
cin >> n;
|
||||
for (int p = 2; p + 2 <= n; p++) {
|
||||
if (isPrime(p) && isPrime(p + 2)) {
|
||||
cout << p << " " << p + 2 << "\n";
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) cout << "NONE";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 枚举上界必须保证 `p+2≤n`;无解情况不能漏掉。
|
||||
|
||||
### 扩展7:函数流水线【略难】
|
||||
|
||||
**题目描述:** 编写三个函数:`digitSum(n)` 求各位和,`isPrime(n)` 判断素数,`countGood(L,R)` 统计区间中“各位和为素数”的整数个数。
|
||||
|
||||
**输入格式:** 输入区间的左端点和右端点。
|
||||
|
||||
**输出格式:** 满足条件的整数个数。
|
||||
|
||||
**数据范围:** `1≤L≤R≤100000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 15
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
3
|
||||
```
|
||||
|
||||
**解题思路:** 10~15 的各位和依次为 1~6,其中 2、3、5 是素数。让 `countGood` 调用 `digitSum`,再把结果交给 `isPrime`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int digitSum(int n) {
|
||||
int sum = 0;
|
||||
while (n > 0) {
|
||||
sum += n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool isPrime(int n) {
|
||||
if (n < 2) return false;
|
||||
for (int i = 2; i * i <= n; i++) {
|
||||
if (n % i == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int countGood(int L, int R) {
|
||||
int count = 0;
|
||||
for (int x = L; x <= R; x++) {
|
||||
if (isPrime(digitSum(x))) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int L, R;
|
||||
cin >> L >> R;
|
||||
cout << countGood(L, R);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 分清每个函数的单一职责;不要在多个位置重复编写同一段逻辑。
|
||||
Reference in New Issue
Block a user