题目.md 5.3 KB

第 2 题:综合大挑战——MyArray 可变数组(动态数组底层实现)⭐⭐⭐⭐⭐

包名:p2_myarray

知识点:构造方法、数组扩容、方法封装、增删改查、元素前移、冒泡排序

模仿 ArrayList 的底层原理,自己动手实现一个可变数组(动态数组)。

需求背景

Java 中普通数组 int[] 一旦创建,长度就固定了,无法动态增减元素。请自行实现一个 可变整型数组 MyArray 类,内部使用 int[] 存储数据,对外提供便捷的增删改查方法。

实体类说明:MyArray

私有属性:

属性 类型 说明
data int[] 内部真正存储数据的数组
size int 当前已存储的元素个数(不是数组长度)

构造方法:

构造方法 说明
MyArray() 无参构造,默认初始化容量为 10 的数组
MyArray(int capacity) 指定初始容量,如果传入的容量 ≤ 0,则使用默认容量 10

核心方法列表(共 11 个)

1. 添加元素 — add(int element)

  • 如果内部数组已满,自动扩容为当前容量的 1.5 倍(data.length * 3 / 2)
  • 扩容步骤:创建新数组 → 复制旧元素 → 替换 data 引用
  • 将新元素存入 data[size],size 自增 1

2. 获取元素 — get(int index)

  • 下标越界时输出 "下标越界,无法获取元素",返回 -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)

  • 从前向后遍历,找到第一个匹配的元素下标,没找到返回 -1

8. 判断是否包含 — contains(int element)

  • 调用 indexOf(),根据返回值是否为 -1 判断

9. 删除指定位置的元素 — remove(int index)

  • 下标越界时输出 "下标越界,无法删除元素",返回 -1
  • 否则:保存被删除的值 → 后面元素前移一位 → size-- → 返回被删除的值

10. 删除指定值的元素 — removeByValue(int element)

  • 调用 indexOf() 获取下标
  • 下标为 -1 则输出 "未找到该元素,删除失败",返回 false
  • 否则调用 remove(index),返回 true

11. 数组排序 — sort(boolean ascending)

  • true 升序,false 降序
  • 使用冒泡排序,只对 data[0] ~ data[size-1] 排序

辅助方法

print()

  • 遍历输出格式:[元素1, 元素2, 元素3, ...]
  • 空数组输出 []

clear()

  • 将 size 置为 0(内部数组保留)

测试类要求

MyArrayTest 类:

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());     // 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
    }
}

思考题

  1. 如果 add() 方法中每次只扩容 1 个容量(data.length + 1),当添加大量元素时性能会怎样?为什么选择 1.5 倍?
  2. remove() 方法中为什么要将后面的元素向前移动?如果删除的是最后一个元素还需要移动吗?
  3. 如何将 MyArray 改造为支持任意类型的 MyArrayList<T>?