Просмотр исходного кода

feat: 新增进阶第11题——MyArray可变数组底层实现(构造方法+数组扩容+增删改查+排序),包含完整方法说明、参考代码骨架、测试用例和挑战加分项

WanJL 1 день назад
Родитель
Сommit
d4eb4ff1eb

+ 12 - 0
授课代码/c260721/src/course/Teacher.java

@@ -0,0 +1,12 @@
+package course;
+
+
+/**
+ * @title Teacher
+ * @description 
+ * @author WanJl
+ * @version 1.0
+ * @create 2026/7/21
+ */
+public class Teacher {
+}

+ 38 - 0
授课代码/c260721/src/exercise/exercise01/Dog.java

@@ -0,0 +1,38 @@
+package exercise;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo01
+ * @description
+ * 练习 2:有参构造方法——Dog 类
+ * 难度:⭐
+ * 知识点:有参构造方法
+ *
+ * 创建一个 Dog 类,包含:
+ *
+ * 私有属性:name(String)、breed(品种,String)
+ * 有参构造方法:Dog(String name, String breed) —— 通过参数为属性赋值
+ * 方法:showInfo() —— 输出 "品种:xxx,名字:xxx"
+ * 测试类要求:使用有参构造方法创建 2 个 Dog 对象,分别调用 showInfo() 输出信息。
+ *
+ * 示例输出:
+ *
+ * 品种:金毛,名字:旺财
+ * 品种:哈士奇,名字:二哈
+ * @create 2026/7/21
+ */
+public class Dog {
+    private String name;
+    private String breed;
+
+    public Dog(String name, String breed){
+        this.name=name;
+        this.breed=breed;
+    }
+    public void showInfo(){
+        System.out.println("品种:"+this.breed+",名字:"+name);
+    }
+
+}

+ 19 - 0
授课代码/c260721/src/exercise/exercise01/DogTest.java

@@ -0,0 +1,19 @@
+package exercise;
+
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title DogTest
+ * @description
+ * @create 2026/7/21
+ */
+public class DogTest {
+    public static void main(String[] args) {
+        Dog d1=new Dog("小美","博美");
+        Dog d2=new Dog("大黄","金毛");
+        d1.showInfo();
+        d2.showInfo();
+
+    }
+}

+ 12 - 0
授课代码/c260721/src/exercise/exercise02/Manager.java

@@ -0,0 +1,12 @@
+package exercise.exercise02;
+
+
+/**
+ * @title Manager
+ * @description 
+ * @author WanJl
+ * @version 1.0
+ * @create 2026/7/21
+ */
+public class Manager {
+}

+ 12 - 0
授课代码/c260721/src/exercise/exercise02/ManagerTest.java

@@ -0,0 +1,12 @@
+package exercise.exercise02;
+
+
+/**
+ * @title ManagerTest
+ * @description 
+ * @author WanJl
+ * @version 1.0
+ * @create 2026/7/21
+ */
+public class ManagerTest {
+}

+ 307 - 0
课堂练习题/20260721-构造方法练习.md

@@ -328,6 +328,312 @@ name = 小咪, age = 1
 
 
 ---
 ---
 
 
+## 第 11 题:综合大挑战——MyArray 可变数组(动态数组底层实现)⭐⭐⭐⭐⭐
+
+> 模仿 `ArrayList` 的底层原理,自己动手实现一个可变数组(动态数组)。本题综合运用 **构造方法、数组扩容、方法封装、排序算法** 等核心知识点。
+
+### 需求背景
+
+Java 中普通数组 `int[]` 一旦创建,长度就固定了,无法动态增减元素。请自行实现一个 **可变整型数组** `MyArray` 类,内部使用 `int[]` 存储数据,对外提供便捷的增删改查方法。
+
+---
+
+### 实体类说明:MyArray
+
+**私有属性**:
+
+| 属性 | 类型 | 说明 |
+|------|------|------|
+| `data` | `int[]` | 内部真正存储数据的数组 |
+| `size` | `int` | 当前已存储的元素个数(不是数组长度) |
+
+**构造方法**:
+
+| 构造方法 | 说明 |
+|---------|------|
+| `MyArray()` | 无参构造,默认初始化容量为 **10** 的数组 |
+| `MyArray(int capacity)` | 指定初始容量,如果传入的容量 ≤ 0,则使用默认容量 10 |
+
+> **提示**:构造方法中只需 `data = new int[capacity]; size = 0;`,不要预填数据。
+
+---
+
+### 核心方法列表
+
+要求实现以下 **11 个方法**:
+
+#### 1. 添加元素 — `add(int element)`
+
+将元素添加到数组的末尾。
+
+- 添加前先检查内部数组是否已满(`size == data.length`)
+- 如果已满,**自动扩容**为当前容量的 **1.5 倍**(即 `data.length * 3 / 2`)
+- 扩容步骤:创建新数组 → 将旧数组元素复制到新数组 → 将新数组赋值给 `data`
+- 最后将新元素存入 `data[size]`,`size` 自增 1
+
+#### 2. 获取元素 — `get(int index)`
+
+返回指定下标处的元素值。
+
+- 如果下标越界(`index < 0 || index >= size`),输出 `"下标越界,无法获取元素"`,返回 `-1`
+- 否则返回 `data[index]`
+
+#### 3. 修改元素 — `set(int index, int element)`
+
+将指定下标处的元素修改为新值。
+
+- 如果下标越界,输出 `"下标越界,无法修改元素"`,不执行修改
+- 否则将 `data[index]` 赋值为 `element`
+
+#### 4. 获取长度 — `size()`
+
+返回当前已存储的元素个数(`size` 属性值)。
+
+#### 5. 获取容量 — `capacity()`
+
+返回内部数组的总长度(`data.length`)。
+
+#### 6. 判断是否为空 — `isEmpty()`
+
+如果 `size == 0` 返回 `true`,否则返回 `false`。
+
+#### 7. 查找元素下标 — `indexOf(int element)`
+
+从前向后遍历数组,查找第一个值与 `element` 相等的元素。
+
+- 如果找到,返回该元素的下标
+- 如果没找到,返回 `-1`
+
+#### 8. 判断是否包含 — `contains(int element)`
+
+调用 `indexOf()` 方法,根据返回值是否为 `-1` 来判断。
+
+#### 9. 删除指定位置的元素 — `remove(int index)`
+
+删除指定下标处的元素。
+
+- 如果下标越界,输出 `"下标越界,无法删除元素"`,返回 `-1`
+- 否则:
+  - 用临时变量保存被删除的元素值
+  - 将 `index` 之后的所有元素向前移动一位(`data[j] = data[j+1]`)
+  - `size` 自减 1
+  - 返回被删除的元素值
+
+> **示意图**(删除下标 2 的元素):
+> ```
+> 删除前:[10, 20, 30, 40, 50]    size=5
+> 删除后:[10, 20, 40, 50, 0]     size=4
+> ```
+
+#### 10. 删除指定值的元素 — `removeByValue(int element)`
+
+删除数组中第一个值与 `element` 相等的元素。
+
+- 调用 `indexOf(element)` 获取下标
+- 如果下标为 `-1`,输出 `"未找到该元素,删除失败"`,返回 `false`
+- 否则调用 `remove(index)` 方法,返回 `true`
+
+#### 11. 数组排序 — `sort(boolean ascending)`
+
+对数组中的元素进行排序。
+
+- 参数 `ascending` 为 `true` 时**升序排列**(小→大),为 `false` 时**降序排列**(大→小)
+- 使用**冒泡排序**或**选择排序**实现
+- 注意:只对已存储的元素(`data[0] ~ data[size-1]`)排序,不要动后面的空闲位置
+
+---
+
+### 辅助方法
+
+#### `print()`
+
+遍历输出数组中的所有元素,格式为 `[元素1, 元素2, 元素3, ...]`。
+
+- 如果数组为空,输出 `[]`
+- 最后一个元素后面不要有逗号
+
+#### `clear()`
+
+清空数组中的所有元素,将 `size` 置为 `0`(内部数组对象保留,不清除)。
+
+---
+
+### 参考代码骨架
+
+```java
+public class MyArray {
+    private int[] data;  // 内部存储数组
+    private int size;    // 当前元素个数
+
+    // 无参构造:默认容量 10
+    public MyArray() {
+        // TODO
+    }
+
+    // 有参构造:指定初始容量
+    public MyArray(int capacity) {
+        // TODO(capacity <= 0 时使用默认容量 10)
+    }
+
+    // 添加元素(自动扩容)
+    public void add(int element) {
+        // TODO
+    }
+
+    // 获取指定位置的元素
+    public int get(int index) {
+        // TODO(下标越界检查)
+        return 0;  // placeholder
+    }
+
+    // 修改指定位置的元素
+    public void set(int index, int element) {
+        // TODO
+    }
+
+    // 获取元素个数
+    public int size() {
+        return size;
+    }
+
+    // 获取数组容量
+    public int capacity() {
+        return data.length;
+    }
+
+    // 判断是否为空
+    public boolean isEmpty() {
+        // TODO
+        return false;
+    }
+
+    // 查找元素下标
+    public int indexOf(int element) {
+        // TODO
+        return -1;
+    }
+
+    // 判断是否包含某元素
+    public boolean contains(int element) {
+        // TODO
+        return false;
+    }
+
+    // 删除指定位置的元素,返回被删除的值
+    public int remove(int index) {
+        // TODO(下标越界检查)
+        return 0;  // placeholder
+    }
+
+    // 删除指定值的元素(第一个匹配项)
+    public boolean removeByValue(int element) {
+        // TODO
+        return false;
+    }
+
+    // 排序(true 升序,false 降序)
+    public void sort(boolean ascending) {
+        // TODO(冒泡排序)
+    }
+
+    // 遍历输出
+    public void print() {
+        // TODO
+    }
+
+    // 清空数组
+    public void clear() {
+        // TODO
+    }
+}
+```
+
+---
+
+### 测试类要求:MyArrayTest
+
+在 `main` 方法中按顺序完成以下操作,并观察输出是否符合预期:
+
+```java
+public class MyArrayTest {
+    public static void main(String[] args) {
+        // 1. 创建一个初始容量为 3 的 MyArray 对象
+        MyArray arr = new MyArray(3);
+
+        // 2. 输出初始状态
+        System.out.println("初始容量:" + arr.capacity());   // 3
+        System.out.println("是否为空:" + arr.isEmpty());     // true
+
+        // 3. 添加 5 个元素(触发自动扩容)
+        for (int i = 1; i <= 5; i++) {
+            arr.add(i * 10);  // 添加 10, 20, 30, 40, 50
+        }
+        arr.print();           // [10, 20, 30, 40, 50]
+
+        // 4. 测试各个方法
+        System.out.println("元素个数:" + arr.size());        // 5
+        System.out.println("当前容量:" + arr.capacity());     // 4(3*1.5=4,再扩容 4*1.5=6)
+        System.out.println("下标2的元素:" + arr.get(2));     // 30
+        System.out.println("是否包含40:" + arr.contains(40)); // true
+        System.out.println("50的下标:" + arr.indexOf(50));   // 4
+
+        // 5. 测试修改
+        arr.set(1, 99);
+        arr.print();           // [10, 99, 30, 40, 50]
+
+        // 6. 测试删除
+        int deleted = arr.remove(2);
+        System.out.println("被删除的元素:" + deleted);       // 30
+        arr.print();           // [10, 99, 40, 50]
+
+        // 7. 测试按值删除
+        arr.removeByValue(10);
+        arr.print();           // [99, 40, 50]
+
+        // 8. 测试升序排序
+        arr.sort(true);
+        arr.print();           // [40, 50, 99]
+
+        // 9. 测试降序排序
+        arr.sort(false);
+        arr.print();           // [99, 50, 40]
+
+        // 10. 测试越界访问
+        System.out.println(arr.get(10));  // 下标越界,无法获取元素 → -1
+        arr.remove(10);                   // 下标越界,无法删除元素 → -1
+
+        // 11. 测试清空
+        arr.clear();
+        System.out.println("清空后是否为空:" + arr.isEmpty()); // true
+        arr.print();           // []
+    }
+}
+```
+
+---
+
+### 挑战加分项(可选)
+
+如果完成了基础版本,可以进一步挑战以下扩展功能:
+
+1. **泛型支持**:将 `MyArray` 改造为支持任意类型的 `MyArrayList<T>`(使用泛型,存储 `Object[]`)
+2. **缩容机制**:当元素个数少于容量的 1/4 时,自动缩容为当前容量的一半(节省内存)
+3. **`getMax()` / `getMin()`**:返回数组中的最大值和最小值
+4. **`addFirst(int element)`**:在数组头部插入元素(所有元素后移)
+5. **`toArray()`**:返回一个包含所有元素的新数组(长度 = size)
+6. **`subList(int fromIndex, int toIndex)`**:返回从 `fromIndex` 到 `toIndex` 的子数组视图
+
+---
+
+> **本题设计思路**:这个练习是模拟 JDK 中 `ArrayList` 的底层实现。通过手写动态数组,你能深刻理解:
+> - 构造方法如何初始化内部数据结构
+> - 数组长度固定的局限性以及「扩容」机制的实现原理
+> - 删除元素时「元素前移」的内存操作细节
+> - 方法封装如何对外提供简洁的 API,隐藏内部实现复杂度
+> - 这是通往「数据结构与算法」的第一级台阶 🪜
+
+---
+
 ## 📋 题目总览
 ## 📋 题目总览
 
 
 | 序号 | 所属部分 | 核心知识点 | 难度 |
 | 序号 | 所属部分 | 核心知识点 | 难度 |
@@ -348,3 +654,4 @@ name = 小咪, age = 1
 | 进阶 8 | 进阶 | 构造方法 + Random + Scanner + 循环 | ⭐⭐⭐⭐ |
 | 进阶 8 | 进阶 | 构造方法 + Random + Scanner + 循环 | ⭐⭐⭐⭐ |
 | 进阶 9 | 进阶 | 构造方法 + 封装 + 对象数组 + 排序 + 查找 | ⭐⭐⭐⭐ |
 | 进阶 9 | 进阶 | 构造方法 + 封装 + 对象数组 + 排序 + 查找 | ⭐⭐⭐⭐ |
 | 进阶 10 | 进阶 | 综合大挑战(构造方法 + 封装 + 包 + 对象数组 + 排序 + 平均分) | ⭐⭐⭐⭐⭐ |
 | 进阶 10 | 进阶 | 综合大挑战(构造方法 + 封装 + 包 + 对象数组 + 排序 + 平均分) | ⭐⭐⭐⭐⭐ |
+| 进阶 11 | 进阶 | MyArray 可变数组(构造方法 + 数组扩容 + 增删改查 + 元素前移 + 冒泡排序 + 方法封装) | ⭐⭐⭐⭐⭐ |