|
|
@@ -1,8 +1,8 @@
|
|
|
-# 2026-08-03 比较器排序专项练习(课堂练习用)
|
|
|
+# 2026-08-03 比较器排序与可变参数专项练习(课堂练习用)
|
|
|
|
|
|
-> **说明**:以下习题围绕今日授课核心内容——**比较器排序(Comparable 自然排序 / Comparator 比较器排序)** 展开,涵盖 Comparable 接口实现与 `compareTo(T o)` 重写、Comparator 接口与匿名内部类、TreeSet/TreeMap 有序集合自动排序、返回值规则(负数存左 / 0 重复不存 / 正数存右)、`Collections.sort(list, comparator)`、`Double.compare`、compareTo 与 equals 一致性等知识点。
|
|
|
+> **说明**:以下习题围绕今日授课核心内容——**比较器排序(Comparable 自然排序 / Comparator 比较器排序)** 与 **可变参数(Varargs)** 展开,涵盖 Comparable 接口实现与 `compareTo(T o)` 重写、Comparator 接口与匿名内部类、TreeSet/TreeMap 有序集合自动排序、返回值规则(负数存左 / 0 重复不存 / 正数存右)、`Collections.sort(list, comparator)`、`Double.compare`、compareTo 与 equals 一致性、可变参数 `形参类型... 参数名`(本质即数组、可变参数必须放最后)等知识点。
|
|
|
>
|
|
|
-> 题目分为 **基础练习**(Comparable 自然排序 / Comparator 比较器排序 / Collections.sort 排序,3 题)和 **进阶挑战**(比较器综合应用,2 题)。
|
|
|
+> 题目分为 **基础练习**(Comparable 自然排序 / Comparator 比较器排序 / Collections.sort 排序 / 可变参数,5 题)和 **进阶挑战**(比较器综合应用,2 题)。
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -173,6 +173,113 @@ public class ListSortTest {
|
|
|
|
|
|
---
|
|
|
|
|
|
+## 练习 4:可变参数基础——任意个数整数求和
|
|
|
+
|
|
|
+**难度**:⭐⭐
|
|
|
+**知识点**:可变参数 `int... a`、`for each` 遍历、方法重载 vs 可变参数、可变参数本质即数组
|
|
|
+
|
|
|
+**场景描述**:以前计算"多个整数相加",有几个参数就要定义几个**方法重载**(`add(int a, int b)` / `add(int a, int b, int c)`...),写多少个都覆盖不完。有了**可变参数**,一个方法就能接收**任意个数**的参数——**方便用户使用,也方便自己定义**。
|
|
|
+
|
|
|
+**题目要求**:
|
|
|
+
|
|
|
+1. 定义 `Calculator` 类,编写可变参数方法 `add(int... a)`,用 for each 累加求和:
|
|
|
+
|
|
|
+```java
|
|
|
+public class Calculator {
|
|
|
+ // TODO: 编写可变参数方法 add(int... a),计算任意个数整数的和
|
|
|
+ // 提示:int sum = 0;
|
|
|
+ // for (int n : a) { sum += n; }
|
|
|
+ // return sum;
|
|
|
+ public int add(int... a) {
|
|
|
+ return 0; // 请补全
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ Calculator calc = new Calculator();
|
|
|
+
|
|
|
+ // 1. 同一个方法,传入不同个数的参数:
|
|
|
+ // add(1, 2) → 3
|
|
|
+ // add(1, 2, 3) → 6
|
|
|
+ // add(1, 2, 3, 4, 5) → 15
|
|
|
+ // add(1,2,...,10) → 55
|
|
|
+
|
|
|
+ // 2. 验证"可变参数本质就是数组":用数组调用,效果与直接传参数一致
|
|
|
+ int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
+ // calc.add(arr) → 55
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**预期输出**:
|
|
|
+```
|
|
|
+add(1, 2) = 3
|
|
|
+add(1, 2, 3) = 6
|
|
|
+add(1, 2, 3, 4, 5) = 15
|
|
|
+add(1~10 累加) = 55
|
|
|
+用数组调用 add(arr) = 55
|
|
|
+```
|
|
|
+
|
|
|
+**思考题**:
|
|
|
+1. `int... a` 和 `int[] a` 是什么关系?为什么两者调用效果一样?(提示:可变参数是数组的语法糖)
|
|
|
+2. 既然有了可变参数,为什么还要方法重载?(提示:参数**个数**不确定用可变参数;参数**个数固定、类型不同**用重载更清晰)
|
|
|
+3. 如果把 `add(int... a)` 改成 `add(int[] a)`,调用时还能写 `add(1, 2, 3)` 吗?(提示:不能,数组参数必须显式传数组)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 练习 5:可变参数进阶——学生成绩统计(固定参数 + 可变参数)
|
|
|
+
|
|
|
+**难度**:⭐⭐
|
|
|
+**知识点**:固定参数与可变参数共存、**可变参数必须放在最后**、求总分/平均分/最大值、可变参数的综合应用
|
|
|
+
|
|
|
+**场景描述**:一个学生有多门课程成绩,成绩**个数不定**。要求:方法同时接收"学生姓名"(固定参数)和"若干门成绩"(可变参数),统计输出总分和平均分。**注意:可变参数必须放在参数列表的最后。**
|
|
|
+
|
|
|
+**题目要求**:
|
|
|
+
|
|
|
+1. 定义 `ScoreCalculator` 类,编写方法 `showScore(String name, int... scores)`:
|
|
|
+
|
|
|
+```java
|
|
|
+public class ScoreCalculator {
|
|
|
+ // TODO: 编写方法 showScore(String name, int... scores)
|
|
|
+ // 1) 输出学生姓名
|
|
|
+ // 2) 遍历 scores 求和(total)和求最大值(max)
|
|
|
+ // 3) 输出各科成绩、总分、平均分(平均分用 double,total * 1.0 / scores.length)
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ ScoreCalculator sc = new ScoreCalculator();
|
|
|
+ sc.showScore("张三", 85, 90, 78); // 3 门课
|
|
|
+ sc.showScore("李四", 92, 88, 95, 80, 90); // 5 门课
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+2. **进阶挑战**:再实现两个可变参数方法,体会通用性:
|
|
|
+ - `max(int... a)`:返回任意个数整数中的最大值
|
|
|
+ - `join(String separator, String... strings)`:用分隔符拼接若干字符串,如 `join("-", "Java", "SE", "260713")` → `"Java-SE-260713"`(注意:固定参数 separator 在前,可变参数在后)
|
|
|
+
|
|
|
+**预期输出**:
|
|
|
+```
|
|
|
+========== 张三的成绩单 ==========
|
|
|
+姓名:张三
|
|
|
+各科成绩:85, 90, 78
|
|
|
+总分:253,平均分:84.33
|
|
|
+最高分:90
|
|
|
+========== 李四的成绩单 ==========
|
|
|
+姓名:李四
|
|
|
+各科成绩:92, 88, 95, 80, 90
|
|
|
+总分:445,平均分:89.0
|
|
|
+最高分:95
|
|
|
+========== 可变参数进阶 ==========
|
|
|
+max(3, 9, 5, 1) = 9
|
|
|
+join("-", "Java", "SE", "260713") = Java-SE-260713
|
|
|
+```
|
|
|
+
|
|
|
+**思考题**:
|
|
|
+1. `showScore(String name, int... scores)` 中,可变参数能写在 name 前面吗?为什么?(提示:可变参数必须放在参数列表最后,否则编译报错)
|
|
|
+2. 如果调用 `showScore("张三")`(不传成绩),`scores.length` 是多少?会不会报错?(提示:可变参数可传 0 个,scores 是长度为 0 的数组)
|
|
|
+3. `join` 方法为什么把分隔符 separator 放在前面、可变参数放后面?如果反过来 `join(String... strings, String separator)` 行吗?(提示:违背"可变参数置末"规则)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
# 第二部分:进阶挑战
|
|
|
|
|
|
> 以下练习综合运用 Comparable / Comparator、TreeMap、compareTo 与 equals 一致性等知识。
|
|
|
@@ -428,6 +535,93 @@ for (Student s : list) {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
+## 练习 4 参考
|
|
|
+
|
|
|
+```java
|
|
|
+public class Calculator {
|
|
|
+ // 可变参数:本质就是 int[] a
|
|
|
+ public int add(int... a) {
|
|
|
+ int sum = 0;
|
|
|
+ for (int n : a) {
|
|
|
+ sum += n;
|
|
|
+ }
|
|
|
+ return sum;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ Calculator calc = new Calculator();
|
|
|
+
|
|
|
+ System.out.println("add(1, 2) = " + calc.add(1, 2));
|
|
|
+ System.out.println("add(1, 2, 3) = " + calc.add(1, 2, 3));
|
|
|
+ System.out.println("add(1, 2, 3, 4, 5) = " + calc.add(1, 2, 3, 4, 5));
|
|
|
+
|
|
|
+ int sum10 = calc.add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
|
|
+ System.out.println("add(1~10 累加) = " + sum10);
|
|
|
+
|
|
|
+ // 可变参数本质就是数组:用数组调用效果一致
|
|
|
+ int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
|
+ System.out.println("用数组调用 add(arr) = " + calc.add(arr));
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 练习 5 参考
|
|
|
+
|
|
|
+```java
|
|
|
+public class ScoreCalculator {
|
|
|
+ // 固定参数 name + 可变参数 scores(可变参数必须放最后)
|
|
|
+ public void showScore(String name, int... scores) {
|
|
|
+ System.out.println("========== " + name + "的成绩单 ==========");
|
|
|
+ System.out.println("姓名:" + name);
|
|
|
+
|
|
|
+ int total = 0;
|
|
|
+ int max = scores[0]; // 假设至少有一门成绩
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (int i = 0; i < scores.length; i++) {
|
|
|
+ total += scores[i];
|
|
|
+ if (scores[i] > max) {
|
|
|
+ max = scores[i];
|
|
|
+ }
|
|
|
+ sb.append(scores[i]).append(i == scores.length - 1 ? "" : ", ");
|
|
|
+ }
|
|
|
+ System.out.println("各科成绩:" + sb);
|
|
|
+ System.out.println("总分:" + total + ",平均分:" + String.format("%.2f", total * 1.0 / scores.length));
|
|
|
+ System.out.println("最高分:" + max);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 进阶:求任意个数整数的最大值
|
|
|
+ public int max(int... a) {
|
|
|
+ int max = a[0];
|
|
|
+ for (int n : a) {
|
|
|
+ if (n > max) max = n;
|
|
|
+ }
|
|
|
+ return max;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 进阶:用分隔符拼接若干字符串(固定参数在前,可变参数在后)
|
|
|
+ public String join(String separator, String... strings) {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (int i = 0; i < strings.length; i++) {
|
|
|
+ sb.append(strings[i]);
|
|
|
+ if (i != strings.length - 1) {
|
|
|
+ sb.append(separator);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ ScoreCalculator sc = new ScoreCalculator();
|
|
|
+ sc.showScore("张三", 85, 90, 78);
|
|
|
+ sc.showScore("李四", 92, 88, 95, 80, 90);
|
|
|
+
|
|
|
+ System.out.println("========== 可变参数进阶 ==========");
|
|
|
+ System.out.println("max(3, 9, 5, 1) = " + sc.max(3, 9, 5, 1));
|
|
|
+ System.out.println("join(\"-\", \"Java\", \"SE\", \"260713\") = " + sc.join("-", "Java", "SE", "260713"));
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
## 进阶 1 参考
|
|
|
|
|
|
```java
|
|
|
@@ -520,4 +714,9 @@ for (Employee e : byName) {
|
|
|
| compareTo 与 equals/hashCode 一致性 | 进阶 1、进阶 2 | compareTo == 0 → equals 返回 true、hashCode 一致 |
|
|
|
| TreeSet 自动排序 + 去重 | 练习 1、进阶 2 | compareTo 返回 0 视为重复,不存入 |
|
|
|
| Iterator 迭代器遍历 | 进阶 2 | Set 没有索引,用迭代器统一遍历 |
|
|
|
+| 可变参数定义与调用 | 练习 4、练习 5 | `int... a` 参数个数可变,一个方法接收任意个数参数 |
|
|
|
+| 可变参数本质即数组 | 练习 4 | `int... a` 等价于 `int[] a`,可用数组直接调用 |
|
|
|
+| 方法重载 vs 可变参数 | 练习 4 | 参数个数不确定用可变参数;个数固定、类型不同用重载 |
|
|
|
+| 固定参数 + 可变参数共存 | 练习 5 | 可变参数必须放在参数列表最后,否则编译报错 |
|
|
|
+| 可变参数综合应用 | 练习 5 | 求总分/平均分/最大值、字符串拼接 join |
|
|
|
|