调整课次结构:前9节重新排序,新建第06课一维数组,后3节不变
This commit is contained in:
109
CLAUDE.md
Normal file
109
CLAUDE.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是一个 **GESP暑假集训教案** 项目,用于少儿编程教学。
|
||||
|
||||
- **课程目标**:巩固GESP一级内容,备战9月等级考试,适当铺垫二级内容
|
||||
- **适合学生**:学过一年C++,基础不扎实,3月一级未通过
|
||||
- **课时安排**:12节课 × 2小时
|
||||
- **考试目标**:9月GESP一级全员通过
|
||||
|
||||
## 教案结构
|
||||
|
||||
### 文件组织
|
||||
|
||||
```
|
||||
10-教案/
|
||||
├── GESP暑假集训教案.md # 课程总纲
|
||||
├── GESP考试大纲整理.md # 考试大纲
|
||||
├── 第01课-数据类型与分支结构/ # 含教师版+学生版
|
||||
├── 第02课-循环结构/ # 含教师版+学生版+编程题
|
||||
├── 第03课-嵌套循环与图形打印/ # 含教师版+学生版+编程题
|
||||
├── 第04课-C++自带函数与数学处理/ # 含教师版+学生版+编程题
|
||||
├── 第05课-自定义函数/ # 含教师版+学生版+编程题
|
||||
├── 第06课-一维数组/ # 含教师版+学生版+编程题
|
||||
├── 第07课-数组运算/ # 含教师版+学生版+编程题
|
||||
├── 第08课-字符串与string/ # 含教师版+学生版+编程题
|
||||
├── 第09课-枚举模拟/ # 含教师版+学生版+编程题
|
||||
├── 第10课-GESP二级真题训练/ # 含教师版+学生版
|
||||
└── docs/ # 旧版教案归档
|
||||
```
|
||||
|
||||
### 课程大纲
|
||||
|
||||
| 节次 | 内容 | 教学目标 |
|
||||
|------|------|----------|
|
||||
| 1 | 数据类型与分支结构 | int/char/double/bool/string + if/else + 打擂台 |
|
||||
| 2 | 循环结构 | for、while、数位拆解、倒序、回文数 |
|
||||
| 3 | 嵌套循环与图形打印 | 外层管行、内层管列、图形规律 |
|
||||
| 4 | C++自带函数与数学处理 | sqrt、abs、pow、max/min、swap、sort + 字符判断 |
|
||||
| 5 | 自定义函数 | 定义/调用/声明、参数传递、返回值、函数重载 |
|
||||
| 6 | 一维数组 | 遍历、查找、统计、逆序、冒泡排序 |
|
||||
| 7 | 数组运算 | 频次统计、最高频查找、去重升序输出 |
|
||||
| 8 | 字符串与 string | 遍历、统计、查找、回文判断 |
|
||||
| 9 | 枚举模拟 | 枚举范围、条件判断、过程模拟 |
|
||||
| 10 | GESP一级真题训练 | 一级真题实战,查漏补缺 |
|
||||
| 11 | GESP二级真题训练一 | 二级真题实战 |
|
||||
| 12 | GESP二级真题训练二 | 二级真题实战,冲刺备考 |
|
||||
|
||||
## 教案内容规范
|
||||
|
||||
### 每节课教案包含
|
||||
|
||||
1. **教学目标** - 明确的学习目标
|
||||
2. **知识点讲解** - 带代码示例的详细讲解
|
||||
3. **打油诗口诀** - 帮助学生记忆的韵律口诀
|
||||
4. **易错点提醒** - 常见错误和注意事项
|
||||
5. **练习题** - 带参考代码的练习题目
|
||||
6. **课后作业** - 巩固练习
|
||||
|
||||
### 打油诗口诀特点
|
||||
|
||||
教案采用打油诗帮助学生记忆算法和知识点,例如:
|
||||
|
||||
**打擂台(求最大值)**
|
||||
> 擂台之上谁最强,先请一位站中央
|
||||
> 逐一比较谁更大,赢者留下当大王
|
||||
|
||||
**累加求和**
|
||||
> 一个一个往里加,循环转完和到家
|
||||
> 初始清零别忘记,累加器里答案大
|
||||
|
||||
## 编辑指南
|
||||
|
||||
### 添加新课程
|
||||
|
||||
1. 创建新文件夹:`第XX课-课程名称/`
|
||||
2. 在文件夹内创建 `教案.md` 文件
|
||||
3. 遵循现有教案的格式和结构
|
||||
4. 更新 `GESP暑假集训教案.md` 中的课程大纲
|
||||
|
||||
### 修改教案内容
|
||||
|
||||
- 保持代码示例的正确性和可运行性
|
||||
- 确保打油诗押韵且易于记忆
|
||||
- 练习题难度适中,符合学生水平
|
||||
- 参考代码要简洁清晰
|
||||
|
||||
### 风格指南
|
||||
|
||||
- 使用中文编写所有面向学生的内容
|
||||
- 代码标识符和关键字使用英文
|
||||
- 保持一致的格式和排版
|
||||
- 每节课的教案长度适中,便于课堂使用
|
||||
|
||||
## GESP考试信息
|
||||
|
||||
- **官方网站**:https://gesp.ccf.org.cn
|
||||
- **刷题平台**:https://www.luogu.com.cn(洛谷)
|
||||
- **考试时长**:120分钟
|
||||
- **满分**:100分
|
||||
- **合格线**:60分
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [GESP考试大纲整理.md](./GESP考试大纲整理.md) - 详细的考试大纲和知识点
|
||||
- [GESP暑假集训教案.md](./GESP暑假集训教案.md) - 课程总纲和打油诗汇总
|
||||
@@ -27,18 +27,18 @@
|
||||
|
||||
| 节次 | 内容 |
|
||||
|------|------|
|
||||
| **1** | **C++自带函数**(sqrt、abs、pow、max/min、swap、sort + 字符判断函数) |
|
||||
| **2** | **自定义函数**(定义/调用/声明、参数传递、返回值、函数重载、局部/全局变量) |
|
||||
| **3** | **数据类型**(int、char、double、bool、string)+ ASCII码 |
|
||||
| **4** | **分支结构**(if、else if、else)+ 打擂台(含二次打擂台) |
|
||||
| **5** | **循环**(for、while、数位拆解、回文数、水仙花数) |
|
||||
| **6** | **嵌套循环与图形打印**(外层管行、内层管列、图形规律) |
|
||||
| **7** | **数组基础**(遍历、查找、统计、逆序、冒泡排序) |
|
||||
| **8** | **字符数组与 string**(遍历、统计、查找、回文判断) |
|
||||
| **9** | **数组计数法**(频次统计、最高频查找、去重升序输出) |
|
||||
| **10** | **枚举与模拟**(枚举范围、条件判断、过程模拟) |
|
||||
| 11 | 综合练习 |
|
||||
| 12 | 模拟考试 + 查漏补缺 |
|
||||
| **1** | **数据类型与分支结构**(int、char、double、bool、string + if/else + 打擂台) |
|
||||
| **2** | **循环结构**(for、while、数位拆解、倒序、回文数) |
|
||||
| **3** | **嵌套循环与图形打印**(外层管行、内层管列、图形规律) |
|
||||
| **4** | **C++自带函数与数学处理**(sqrt、abs、pow、max/min、swap、sort + 字符判断函数) |
|
||||
| **5** | **自定义函数**(定义/调用/声明、参数传递、返回值、函数重载、局部/全局变量) |
|
||||
| **6** | **一维数组**(遍历、查找、统计、逆序、冒泡排序) |
|
||||
| **7** | **数组运算**(频次统计、最高频查找、去重升序输出) |
|
||||
| **8** | **字符串与 string**(遍历、统计、查找、回文判断) |
|
||||
| **9** | **枚举模拟**(枚举范围、条件判断、过程模拟) |
|
||||
| 10 | GESP一级真题训练 |
|
||||
| 11 | GESP二级真题训练一 |
|
||||
| 12 | GESP二级真题训练二 |
|
||||
|
||||
> 每节课含 2-3 道经典题目,其中 1 道由橙子(我)完整编写,其余由橙子自选补充。
|
||||
|
||||
@@ -47,9 +47,53 @@
|
||||
每节课一个文件夹,内含教师版和学生版两个文件:
|
||||
|
||||
```
|
||||
第01课-C++自带函数/
|
||||
第01课-数据类型与分支结构/
|
||||
├── 教案-教师版.md ← 完整内容
|
||||
└── 教案-学生版.md ← 关键内容留空(学生填写)
|
||||
|
||||
第02课-循环结构/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第03课-嵌套循环与图形打印/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第04课-C++自带函数与数学处理/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第05课-自定义函数/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第06课-一维数组/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第07课-数组运算/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第08课-字符串与string/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第09课-枚举模拟/
|
||||
├── 教案-教师版.md
|
||||
├── 教案-学生版.md
|
||||
└── 编程题-教师版.md
|
||||
|
||||
第10课-GESP二级真题训练/
|
||||
├── 教案-教师版.md
|
||||
└── 教案-学生版.md
|
||||
```
|
||||
|
||||
### 教师版 vs 学生版
|
||||
|
||||
158
第06课-一维数组/教案-学生版.md
Normal file
158
第06课-一维数组/教案-学生版.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 第6课:一维数组
|
||||
|
||||
## 教学目标
|
||||
- 掌握一维数组的定义、初始化和访问
|
||||
- 能使用数组进行遍历、查找、统计等基本操作
|
||||
- 理解数组逆序和冒泡排序的原理
|
||||
|
||||
## 核心考点:数组下标、遍历与越界
|
||||
|
||||
### 考什么
|
||||
使用数组完成读入、统计、查找和排序,并判断每个元素对应的________。
|
||||
|
||||
### 必须理解
|
||||
长度为 n 的数组,合法下标从________到________。`arr[i]` 表示第________个元素。访问 `arr[n]` 会发生________。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
for (int i = ________; i < ________; i++) cin >> arr[i];
|
||||
|
||||
int maximum = ________;
|
||||
for (int i = ________; i < n; i++) {
|
||||
if (arr[i] > maximum) ____________________;
|
||||
}
|
||||
```
|
||||
|
||||
### 常见错误
|
||||
- `i <= n` 为什么会越界?________________
|
||||
- 全是负数时,最大值能否初始化为0?________________
|
||||
- "第5个元素"的下标是多少?________
|
||||
|
||||
### 判断是否掌握
|
||||
- [ ] 我能说出数组的首尾合法下标。
|
||||
- [ ] 我能写出无越界的遍历循环。
|
||||
- [ ] 我能用数组完成查找和打擂台。
|
||||
|
||||
---
|
||||
|
||||
## 题目一:数组入门 — 求最大值与平均值
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 数组遍历的核心:**`______`**,下标从 ______ 开始,到 ______ 结束;打擂台求最值,先请 ______ 当擂主。
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n
|
||||
2. 定义数组 ______
|
||||
3. for i = 0 到 ______:
|
||||
4. 输入 ______ // 读入数组
|
||||
5. maxVal = ______ // 擂主
|
||||
6. sum = ______
|
||||
7. for i = ______ 到 ______:
|
||||
8. if arr[i] ______ maxVal: // 打擂
|
||||
9. maxVal = ______
|
||||
10. sum += ______ // 累加
|
||||
11. avg = ________________ // 整数转浮点数
|
||||
12. 输出 maxVal 和 avg
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
|
||||
```
|
||||
|
||||
### 注意点
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 题目二:查找元素 — 找目标值
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 查找的核心:**遍历 + 比较 + ______**,找到了就记录位置并退出,用一个 ______ 表示"没找到"。
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n, 数组 arr, target
|
||||
2. index = ______ // 哨兵:默认没找到
|
||||
3. for i = 0 到 ______:
|
||||
4. if arr[i] ______ target:
|
||||
5. index = ______
|
||||
6. ______ // 找到就停
|
||||
7. if index ______ -1:
|
||||
8. 输出 "找到,下标:" + index
|
||||
9. else:
|
||||
10. 输出 "未找到"
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
|
||||
```
|
||||
|
||||
### 注意点
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 题目三:数组逆序与冒泡排序
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 逆序的核心:**首尾交换,只换 ______**;冒泡排序的核心:**相邻两两比较,______**,每轮确定一个最大值的位置。
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
|
||||
|
||||
### 伪代码
|
||||
|
||||
**数组逆序**:
|
||||
```
|
||||
1. for i = 0 到 ______:
|
||||
2. temp = ______
|
||||
3. arr[i] = ______
|
||||
4. arr[______] = temp
|
||||
```
|
||||
|
||||
**冒泡排序**:
|
||||
```
|
||||
1. for i = 0 到 ______: // 外层:第 i 轮
|
||||
2. for j = 0 到 ______: // 内层:相邻比较
|
||||
3. if arr[j] ______ arr[j+1]:// 前面大就交换
|
||||
4. temp = ______
|
||||
5. arr[j] = ______
|
||||
6. arr[j+1] = ______
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
|
||||
```
|
||||
|
||||
### 注意点
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 本课打油诗
|
||||
|
||||
>
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
1. 输入 n 个数,求第二大值(注意可能有重复最大值)
|
||||
2. 输入 n 个数,将它们逆序存储后输出(不能用第二个数组)
|
||||
3. 输入 n 个数,统计其中不同数字的个数
|
||||
4. 输入 n 个数,使用冒泡排序从小到大排序后输出
|
||||
300
第06课-一维数组/教案-教师版.md
Normal file
300
第06课-一维数组/教案-教师版.md
Normal file
@@ -0,0 +1,300 @@
|
||||
# 第6课:一维数组
|
||||
|
||||
## 教学目标
|
||||
- 掌握一维数组的定义、初始化和访问
|
||||
- 能使用数组进行遍历、查找、统计等基本操作
|
||||
- 理解数组逆序和冒泡排序的原理
|
||||
|
||||
## 核心考点:数组下标、遍历与越界
|
||||
|
||||
### 考什么
|
||||
考试常要求读入一组数据并完成求和、最值、查找、逆序或排序,也会直接考某个下标对应哪个元素。所有数组题的基础都是正确理解下标范围并完整遍历。
|
||||
|
||||
### 必须理解
|
||||
长度为 n 的数组包含 n 个元素,但合法下标是 `0~n-1`。`arr[i]` 表示第 i+1 个元素,而不是第 i 个元素。遍历通常写成 `for (int i=0; i<n; i++)`,这样第一个和最后一个元素都恰好访问一次。数组不会自动检查越界;访问 `arr[n]` 已经超出范围,可能读到垃圾值或破坏其他数据。打擂台求最值时,最安全的初值通常是 `arr[0]`,再从下标1开始比较。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
int arr[100];
|
||||
for (int i = 0; i < n; i++) cin >> arr[i];
|
||||
|
||||
int maximum = arr[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (arr[i] > maximum) maximum = arr[i];
|
||||
}
|
||||
```
|
||||
数组容量要不小于 n,循环条件必须是 `i < n`。
|
||||
|
||||
### 常见错误
|
||||
- 写成 `i <= n`,最后访问到不存在的 `arr[n]`。
|
||||
- 把"第几个元素"和"下标是多少"混为一谈。
|
||||
- 最大值初始化为0,遇到全负数数组时得到错误答案。
|
||||
- 使用未初始化的数组元素参与计算。
|
||||
|
||||
### 判断是否掌握
|
||||
给定数组长度 n,能立即说出首尾下标,能写出无越界的输入和遍历循环,并能正确完成查找、统计或打擂台。
|
||||
|
||||
---
|
||||
|
||||
## 题目一:数组入门 — 求最大值与平均值
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 数组遍历的核心:**`for (i = 0; i < n; i++)`**,下标从 0 开始,到 n-1 结束;打擂台求最值,先请第一个当擂主。
|
||||
|
||||
### 自然语言思路
|
||||
老师手上有 n 个分数,要找出最高分和平均分。
|
||||
|
||||
第一步,把 n 个分数先存进数组 `arr[0]` 到 `arr[n-1]`,用 `cin` 配合 `for` 循环读入。
|
||||
第二步,求最大值用"打擂台":先假设 `arr[0]` 是最大的(擂主),然后从 `arr[1]` 开始逐个挑战,谁更大谁就当新擂主。
|
||||
第三步,求平均值:先把所有元素加到一起(累加器初始为 0),循环一遍累加,最后除以 n。
|
||||
第四步,注意平均值可能是小数,要用 `double` 类型,整数除整数会丢掉小数部分。
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n
|
||||
2. 定义数组 arr[n]
|
||||
3. for i = 0 到 n-1:
|
||||
4. 输入 arr[i] // 读入数组
|
||||
5. maxVal = arr[0] // 擂主
|
||||
6. sum = 0
|
||||
7. for i = 0 到 n-1:
|
||||
8. if arr[i] > maxVal: // 打擂
|
||||
9. maxVal = arr[i]
|
||||
10. sum += arr[i] // 累加
|
||||
11. avg = (double)sum / n // 整数转浮点数
|
||||
12. 输出 maxVal 和 avg
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
int arr[n];
|
||||
|
||||
// 读入数组
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> arr[i];
|
||||
}
|
||||
|
||||
// 打擂台求最大值
|
||||
int maxVal = arr[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (arr[i] > maxVal) {
|
||||
maxVal = arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 累加求和
|
||||
int sum = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
sum += arr[i];
|
||||
}
|
||||
double avg = (double)sum / n; // 强转,保留小数
|
||||
|
||||
cout << "最大值:" << maxVal << endl;
|
||||
cout << "平均值:" << avg << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **下标从 0 开始**:`arr[0]` 是第一个元素,`arr[n-1]` 是最后一个。这是新手最容易犯的错。
|
||||
2. **打擂台循环从 1 开始**:`for (i = 1; i < n; i++)`,因为 `arr[0]` 已经是擂主了,不用跟自己比。
|
||||
3. **整数除法陷阱**:`sum / n` 两个 int 相除会丢掉小数,必须把其中一个转成 `double`。
|
||||
4. **数组大小**:`int arr[n]` 在部分老编译器(如 VC6)上不支持变长数组,可以用 `int arr[1000]` 设一个大一点的固定值。
|
||||
|
||||
---
|
||||
|
||||
## 题目二:查找元素 — 找目标值
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 查找的核心:**遍历 + 比较 + break**,找到了就记录位置并退出,用一个 -1 表示"没找到"。
|
||||
|
||||
### 自然语言思路
|
||||
在一个数组里找某个数,就像在一排抽屉里找东西。
|
||||
|
||||
第一步,设一个标记 `index = -1`,表示"还没找到"(-1 不可能是合法下标,所以用它当哨兵)。
|
||||
第二步,从第一个到最后一个,逐个打开抽屉 `arr[i]`,跟目标值比。
|
||||
第三步,一旦找到,记录下标 `index = i`,立刻 `break` 退出循环,不浪费时间。
|
||||
第四步,循环结束后,如果 `index` 还是 -1 就是没找到,否则输出下标。
|
||||
|
||||
> 也叫"顺序查找"或"线性查找",像沿着一条线逐个摸过去。
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n, 数组 arr, target
|
||||
2. index = -1 // 哨兵:默认没找到
|
||||
3. for i = 0 到 n-1:
|
||||
4. if arr[i] == target:
|
||||
5. index = i
|
||||
6. break // 找到就停
|
||||
7. if index != -1:
|
||||
8. 输出 "找到,下标:" + index
|
||||
9. else:
|
||||
10. 输出 "未找到"
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, target;
|
||||
cin >> n;
|
||||
int arr[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> arr[i];
|
||||
}
|
||||
cin >> target;
|
||||
|
||||
int index = -1; // 哨兵
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (arr[i] == target) {
|
||||
index = i;
|
||||
break; // 找到就停
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
cout << "找到,下标为:" << index << endl;
|
||||
} else {
|
||||
cout << "未找到" << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **哨兵值选 -1**:因为数组下标从 0 开始,-1 永远不可能是合法下标,所以用它表示"没找到"很安全。
|
||||
2. **break 的作用**:找到后立刻停止,不需要继续往后找了。如果忘了加 `break`,会找到最后一次出现的位置。
|
||||
3. **如果找第一个出现的位置**:加 `break`;**如果找最后一次出现的位置**:不加 `break`,让循环跑完。
|
||||
|
||||
---
|
||||
|
||||
## 题目三:数组逆序与冒泡排序
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 逆序的核心:**首尾交换,只换一半**;冒泡排序的核心:**相邻两两比较,大的往后冒**,每轮确定一个最大值的位置。
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
**数组逆序**:
|
||||
第一步,想象把数组对折:第 0 个和第 n-1 个交换,第 1 个和第 n-2 个交换……
|
||||
第二步,循环只需要跑 `n / 2` 次,因为每次交换两个元素。
|
||||
第三步,交换用三行代码(中间变量法):`temp = a; a = b; b = temp;`。
|
||||
|
||||
**冒泡排序**:
|
||||
第一步,外层循环决定"第几轮",一共需要 n-1 轮。
|
||||
第二步,每轮从数组开头开始,相邻两个比大小:如果前面的 > 后面的,就交换。
|
||||
第三步,每轮结束,最大的那个数就"冒"到了最后面。所以下一轮可以少比一个(`j < n-1-i`)。
|
||||
第四步,n-1 轮过后,数组从小到大排好了。
|
||||
|
||||
### 伪代码
|
||||
|
||||
**数组逆序**:
|
||||
```
|
||||
1. for i = 0 到 n/2 - 1:
|
||||
2. temp = arr[i]
|
||||
3. arr[i] = arr[n-1-i]
|
||||
4. arr[n-1-i] = temp
|
||||
```
|
||||
|
||||
**冒泡排序**:
|
||||
```
|
||||
1. for i = 0 到 n-2: // 外层:第 i 轮
|
||||
2. for j = 0 到 n-2-i: // 内层:相邻比较
|
||||
3. if arr[j] > arr[j+1]: // 前面大就交换
|
||||
4. temp = arr[j]
|
||||
5. arr[j] = arr[j+1]
|
||||
6. arr[j+1] = temp
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
|
||||
**数组逆序**:
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
int arr[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> arr[i];
|
||||
}
|
||||
|
||||
// 首尾交换,只换一半
|
||||
for (int i = 0; i < n / 2; i++) {
|
||||
int temp = arr[i];
|
||||
arr[i] = arr[n - 1 - i];
|
||||
arr[n - 1 - i] = temp;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
cout << arr[i] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**冒泡排序**:
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
int arr[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> arr[i];
|
||||
}
|
||||
|
||||
// 冒泡排序
|
||||
for (int i = 0; i < n - 1; i++) { // 外层:n-1 轮
|
||||
for (int j = 0; j < n - 1 - i; j++) { // 内层:每轮少比一个
|
||||
if (arr[j] > arr[j + 1]) { // 前面大则交换
|
||||
int temp = arr[j];
|
||||
arr[j] = arr[j + 1];
|
||||
arr[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
cout << arr[i] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **逆序循环次数**:`n / 2`,不是 `n`。如果是奇数个元素,中间那个不用换。例如 n=5,只需换 2 次(下标 0↔4,1↔3)。
|
||||
2. **冒泡内层循环上界**:`n - 1 - i`,不是 `n - 1`。每轮少比一个是因为最后面已经排好了。
|
||||
3. **冒泡时间复杂度**:n 个数大概要比 n² / 2 次,数据量大时较慢。学完 sort 后可以直接用 `sort` 替代冒泡。
|
||||
4. **交换三行口诀**:`temp = 前; 前 = 后; 后 = temp;` —— 中间变量暂存,避免覆盖丢失。
|
||||
|
||||
---
|
||||
|
||||
## 本课打油诗
|
||||
|
||||
> 数组元素排排坐,下标从零开始摸。
|
||||
> 遍历循环 for 一把,一个不落全看过。
|
||||
> 擂台之上比高矮,先请一位站中央。
|
||||
> 首尾交换逆序成,冒泡大的往后挪。
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
1. 输入 n 个数,求第二大值(注意可能有重复最大值)
|
||||
2. 输入 n 个数,将它们逆序存储后输出(不能用第二个数组)
|
||||
3. 输入 n 个数,统计其中不同数字的个数
|
||||
4. 输入 n 个数,使用冒泡排序从小到大排序后输出
|
||||
677
第06课-一维数组/编程题-教师版.md
Normal file
677
第06课-一维数组/编程题-教师版.md
Normal file
@@ -0,0 +1,677 @@
|
||||
# 第6课编程题(教师版)
|
||||
|
||||
## 本课知识点覆盖表
|
||||
|
||||
| 核心知识点 | GESP等级 | 对应课堂题 |
|
||||
|---|---|---|
|
||||
| 数组定义、初始化、合法下标、遍历与平均值 | 三级工具 | 课堂1 |
|
||||
| 顺序查找、首次与末次位置、哨兵值 | 三级工具 | 课堂2 |
|
||||
| 分类统计、打擂台求最值及下标 | 三级工具 | 课堂3 |
|
||||
| 原地逆序、直接调用 `sort` 完成升序 | 三级工具 | 课堂4 |
|
||||
|
||||
## 一、课堂练习(4题)
|
||||
|
||||
### 课堂1:成绩分析报告【适中】
|
||||
|
||||
**题目描述:** 输入若干成绩,输出总分、平均分、最高分和最低分。平均分保留两位小数。
|
||||
|
||||
**输入格式:** 第一行输入学生人数;第二行输入每名学生的成绩。
|
||||
|
||||
**输出格式:** 依次输出总分、平均分、最高分和最低分。
|
||||
|
||||
**数据范围:** 学生人数为 1~100,成绩为 0~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
80 95 70 85 90
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
420 84.00 95 70
|
||||
```
|
||||
|
||||
**解题思路:** 用数组保存数据并完整遍历;总分从 0 开始,最值用第一个元素初始化。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[105], sum = 0;
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
int biggest = a[0], smallest = a[0];
|
||||
for (int i = 0; i < n; i++) {
|
||||
sum += a[i];
|
||||
if (a[i] > biggest) biggest = a[i];
|
||||
if (a[i] < smallest) smallest = a[i];
|
||||
}
|
||||
cout << sum << " " << fixed << setprecision(2)
|
||||
<< 1.0 * sum / n << " " << biggest << " " << smallest;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 长度为学生人数的数组,最后一个合法下标是人数减 1。
|
||||
|
||||
### 课堂2:目标值的位置【适中】
|
||||
|
||||
**题目描述:** 输入一个数组和目标值,输出目标值第一次出现的位置、最后一次出现的位置和出现次数。位置从 1 开始;没有出现时输出 `-1 -1 0`。
|
||||
|
||||
**输入格式:** 第一行输入数组长度和目标值;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 第一次位置、最后一次位置和出现次数。
|
||||
|
||||
**数据范围:** 数组长度为 1~1000,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
7 5
|
||||
2 5 3 5 5 8 1
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
2 5 3
|
||||
```
|
||||
|
||||
**解题思路:** 第一次位置初始化为 -1;遍历时首次命中记录第一次位置,每次命中都更新最后位置并计数。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, target, a[1005];
|
||||
cin >> n >> target;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
int first = -1, last = -1, count = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (a[i] == target) {
|
||||
if (first == -1) first = i + 1;
|
||||
last = i + 1;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
cout << first << " " << last << " " << count;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 数组下标从 0 开始,题目位置从 1 开始,输出时需要加 1。
|
||||
|
||||
### 课堂3:最优秀的进步者【适中】
|
||||
|
||||
**题目描述:** 输入每名学生上次和本次成绩,输出进步分数最大的学生编号;若并列,选择本次成绩更高者;仍并列选择编号更小者。
|
||||
|
||||
**输入格式:** 第一行输入学生人数;第二行输入上次成绩;第三行输入本次成绩。
|
||||
|
||||
**输出格式:** 学生编号和进步分数。
|
||||
|
||||
**数据范围:** 学生人数为 1~100,成绩为 0~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
4
|
||||
60 70 80 50
|
||||
80 85 90 70
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 20
|
||||
```
|
||||
|
||||
**解题思路:** 两个数组保存两次成绩;用第一名学生初始化擂主,再按进步值、本次成绩、编号依次比较。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, oldScore[105], newScore[105];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> oldScore[i];
|
||||
for (int i = 0; i < n; i++) cin >> newScore[i];
|
||||
int best = 0;
|
||||
for (int i = 1; i < n; i++) {
|
||||
int progress = newScore[i] - oldScore[i];
|
||||
int bestProgress = newScore[best] - oldScore[best];
|
||||
if (progress > bestProgress ||
|
||||
(progress == bestProgress && newScore[i] > newScore[best])) {
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
cout << best + 1 << " " << newScore[best] - oldScore[best];
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 并列规则中编号更小者优先,因此前两项相同就不更新。
|
||||
|
||||
### 课堂4:逆序后升序排列【适中】
|
||||
|
||||
**题目描述:** 输入一个数组,先在原数组中首尾交换完成逆序并输出;再直接调用 `sort` 将它升序排列并输出。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 第一行输出逆序数组;第二行输出升序数组。
|
||||
|
||||
**数据范围:** 数组长度为 1~100,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
4 1 3 5 2
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
2 5 3 1 4
|
||||
1 2 3 4 5
|
||||
```
|
||||
|
||||
**解题思路:** 逆序只交换一半;需要排序时直接调用 `sort`,本课不学习手写排序算法。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
void printArray(int a[], int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n, a[105];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
for (int i = 0; i < n / 2; i++) {
|
||||
int temp = a[i];
|
||||
a[i] = a[n - 1 - i];
|
||||
a[n - 1 - i] = temp;
|
||||
}
|
||||
printArray(a, n);
|
||||
sort(a, a + n);
|
||||
printArray(a, n);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 逆序下标配对为当前位置与"长度减 1 再减当前位置";`sort` 的结束位置写数组名加长度。
|
||||
|
||||
## 二、课后作业(3题)
|
||||
|
||||
### 课后1:数组求和【简单】
|
||||
|
||||
**题目描述:** 输入一个整数数组,输出所有元素之和。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 所有元素之和。
|
||||
|
||||
**数据范围:** 数组长度为 1~1000,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
4
|
||||
3 6 2 9
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
20
|
||||
```
|
||||
|
||||
**解题思路:** 遍历数组并累加。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[1005];
|
||||
long long sum = 0;
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> a[i];
|
||||
sum += a[i];
|
||||
}
|
||||
cout << sum;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 元素之和可能较大,累加器使用 `long long`。
|
||||
|
||||
### 课后2:统计正负零【简单】
|
||||
|
||||
**题目描述:** 输入一个数组,分别统计正数、负数和零的个数。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 依次输出正数、负数和零的个数。
|
||||
|
||||
**数据范围:** 数组长度为 1~1000。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
6
|
||||
-2 0 5 7 0 -1
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
2 2 2
|
||||
```
|
||||
|
||||
**解题思路:** 遍历时使用三分支更新三个计数器。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[1005], positive = 0, negative = 0, zero = 0;
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (a[i] > 0) positive++;
|
||||
else if (a[i] < 0) negative++;
|
||||
else zero++;
|
||||
}
|
||||
cout << positive << " " << negative << " " << zero;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 三种情况互斥,应使用 `if-else if-else`。
|
||||
|
||||
### 课后3:原地逆序【简单】
|
||||
|
||||
**题目描述:** 不使用第二个数组,将输入数组逆序后输出。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 逆序后的数组。
|
||||
|
||||
**数据范围:** 数组长度为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
4
|
||||
10 20 30 40
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
40 30 20 10
|
||||
```
|
||||
|
||||
**解题思路:** 交换首尾对应元素,只需循环数组长度的一半。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[105];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
for (int i = 0; i < n / 2; i++) {
|
||||
int temp = a[i];
|
||||
a[i] = a[n - 1 - i];
|
||||
a[n - 1 - i] = temp;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 若交换整个数组长度,会把已经交换好的元素再换回来。
|
||||
|
||||
## 三、扩展练习(7题)
|
||||
|
||||
### 扩展1:循环左移一位【基础综合】
|
||||
|
||||
**题目描述:** 将数组所有元素循环左移一位,第一个元素移到最后。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 移动后的数组。
|
||||
|
||||
**数据范围:** 数组长度为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
1 2 3 4 5
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
2 3 4 5 1
|
||||
```
|
||||
|
||||
**解题思路:** 暂存第一个元素,依次用后一个元素覆盖前一个位置,最后放回暂存值。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[105];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
int first = a[0];
|
||||
for (int i = 0; i < n - 1; i++) a[i] = a[i + 1];
|
||||
a[n - 1] = first;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 必须先保存第一个元素,否则移动后会丢失。
|
||||
|
||||
### 扩展2:第二大不同值【中等】
|
||||
|
||||
**题目描述:** 输出数组中第二大的不同数;若不存在两个不同数,输出 `NONE`。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 第二大的不同数或 `NONE`。
|
||||
|
||||
**数据范围:** 数组长度为 1~100,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
6
|
||||
5 8 8 3 5 7
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
7
|
||||
```
|
||||
|
||||
**解题思路:** 先调用 `sort` 升序,再从倒数第二个位置向前寻找第一个小于最大值的元素。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[105];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
sort(a, a + n);
|
||||
int index = n - 2;
|
||||
while (index >= 0 && a[index] == a[n - 1]) index--;
|
||||
if (index < 0) cout << "NONE";
|
||||
else cout << a[index];
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** "第二大"指第二大的不同值,重复最大值不能算作答案。
|
||||
|
||||
### 扩展3:指定位置插入【中等】
|
||||
|
||||
**题目描述:** 在数组的指定位置插入一个整数,原位置及后续元素依次后移。位置从 1 开始。
|
||||
|
||||
**输入格式:** 第一行输入原数组长度;第二行输入数组元素;第三行输入插入位置和插入值。
|
||||
|
||||
**输出格式:** 插入后的数组。
|
||||
|
||||
**数据范围:** 原数组长度为 1~99,插入位置合法。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
4
|
||||
10 20 30 40
|
||||
3 25
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
10 20 25 30 40
|
||||
```
|
||||
|
||||
**解题思路:** 从数组末尾向插入位置倒序移动,避免覆盖尚未搬走的元素。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[105], position, value;
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
cin >> position >> value;
|
||||
int index = position - 1;
|
||||
for (int i = n; i > index; i--) a[i] = a[i - 1];
|
||||
a[index] = value;
|
||||
n++;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 插入时必须从后向前移动;从前向后会反复覆盖数据。
|
||||
|
||||
### 扩展4:删除所有目标值【中等】
|
||||
|
||||
**题目描述:** 删除数组中所有等于目标值的元素,并保持其余元素原有顺序。
|
||||
|
||||
**输入格式:** 第一行输入数组长度和目标值;第二行输入数组元素。
|
||||
|
||||
**输出格式:** 删除后的数组;若数组为空,输出 `EMPTY`。
|
||||
|
||||
**数据范围:** 数组长度为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
7 3
|
||||
1 3 2 3 3 5 4
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 2 5 4
|
||||
```
|
||||
|
||||
**解题思路:** 用写入位置记录保留下来的元素个数,遇到非目标值就写到数组前部。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, target, a[105], length = 0;
|
||||
cin >> n >> target;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (a[i] != target) a[length++] = a[i];
|
||||
}
|
||||
if (length == 0) cout << "EMPTY";
|
||||
else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 新长度与原数组下标含义不同,不要遗漏最后得到的新长度。
|
||||
|
||||
### 扩展5:排序后去重【中等】
|
||||
|
||||
**题目描述:** 输入一个整数数组,直接调用 `sort` 升序排列,然后只保留每个数的第一次出现,输出去重后的结果。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组中的所有整数。
|
||||
|
||||
**输出格式:** 第一行输出去重后的元素个数;第二行按升序输出去重结果。
|
||||
|
||||
**数据范围:** 数组长度为 1~1000,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
7
|
||||
3 1 3 2 1 5 2
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
4
|
||||
1 2 3 5
|
||||
```
|
||||
|
||||
**解题思路:** 排序后相同元素会相邻;第一个元素直接保留,后续元素与上一个元素不同才写入数组前部。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[1005];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
sort(a, a + n);
|
||||
int length = 1;
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (a[i] != a[length - 1]) a[length++] = a[i];
|
||||
}
|
||||
cout << length << "\n";
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i) cout << " ";
|
||||
cout << a[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 先排序才能通过比较相邻元素去重;新长度初始为 1。
|
||||
|
||||
### 扩展6:中位数【略难】
|
||||
|
||||
**题目描述:** 输入一个整数数组,直接调用 `sort` 后求中位数。元素个数为奇数时取中间值;为偶数时取中间两个数的平均值,保留一位小数。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入数组元素。
|
||||
|
||||
**输出格式:** 中位数,保留一位小数。
|
||||
|
||||
**数据范围:** 数组长度为 1~200,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
6
|
||||
7 1 9 3 5 11
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
6.0
|
||||
```
|
||||
|
||||
**解题思路:** 先升序排序;奇数长度访问中间下标,偶数长度计算两个中间元素平均值。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[205];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
sort(a, a + n);
|
||||
double median;
|
||||
if (n % 2 == 1) median = a[n / 2];
|
||||
else median = (a[n / 2 - 1] + a[n / 2]) / 2.0;
|
||||
cout << fixed << setprecision(1) << median;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 偶数长度的两个中间下标是"长度除以 2 减 1"和"长度除以 2"。
|
||||
|
||||
### 扩展7:最小差值数对【略难】
|
||||
|
||||
**题目描述:** 输入互不相同的整数,找出差的绝对值最小的两个数,按从小到大输出;若多对差值相同,输出较小数字更小的一对。
|
||||
|
||||
**输入格式:** 第一行输入数组长度;第二行输入所有互不相同的整数。
|
||||
|
||||
**输出格式:** 满足条件的两个数和它们的差值。
|
||||
|
||||
**数据范围:** 数组长度为 2~200,元素绝对值不超过一万。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
8 1 15 5 3
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 3 2
|
||||
```
|
||||
|
||||
**解题思路:** 先调用 `sort` 升序;最小差值一定出现在相邻元素之间,再用打擂台处理并列规则。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, a[205];
|
||||
cin >> n;
|
||||
for (int i = 0; i < n; i++) cin >> a[i];
|
||||
sort(a, a + n);
|
||||
int best = 0;
|
||||
for (int i = 1; i < n - 1; i++) {
|
||||
if (a[i + 1] - a[i] < a[best + 1] - a[best])
|
||||
best = i;
|
||||
}
|
||||
cout << a[best] << " " << a[best + 1] << " "
|
||||
<< a[best + 1] - a[best];
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 排序后只需比较相邻元素;差值相同时不更新即可保留较小的一对。
|
||||
Reference in New Issue
Block a user