程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 数据结构

    • 时间复杂度
    • 初识集合
    • List接口
    • Set接口
    • Queue接口
    • Map接口
    • Collections工具类
    • 模拟实现ArrayList
      • 1.定义顺序顺序表
      • 2. 函数实现
        • 2.1 display(打印)
        • 2.2 add(新增)
        • 2.3 add(指定位置新增)
        • 2.4 contains(包含)
        • 2.5 indexOf(查找)
        • 2.6 get(获取指定位置)
        • 2.7 set(更新指定位置)
        • 2.8 remove(删除指定key)
        • 2.9 size (长度)
        • 2.10 clear(清空)
        • 2.11 异常的定义
      • 3.测试代码
    • 单向链表的实现
    • 双向链表的实现
    • 树和二叉树的实现
    • 二叉搜索树的实现
  • Java数据结构
  • 数据结构
scholar
2024-03-24
目录

模拟实现ArrayList

ArrayList是Java集合框架(java.util包)的一部分,是一个基于数组实现的列表类,提供了动态数组的功能。与Java的普通数组相比,ArrayList的容量能够自动增长,这使得使用者无需在使用前确定数组的大小。

一. 模拟实现ArrayList

下载 (4)

我们这里是模拟实现,所以实现基本功能即可

下载

# 1.定义顺序顺序表

  • elem:一个整型数组,用于存储MyArrayList中的元素。
  • usedSize:表示MyArrayList当前存储的元素个数。
  • DEFAULT_SIZE:MyArrayList的默认容量,用于在构造方法中初始化数组的大小。
  • 构造方法MyArrayList():创建一个默认容量为DEFAULT_SIZE的数组,并将usedSize初始化为0。
public class MyArrayList {
 
    public int[] elem; // 存储元素的数组
    public int usedSize; // 当前数组中包含的元素个数
    private static final int DEFAULT_SIZE = 10; // 默认数组容量
 
    // 构造方法,初始化数组容量为DEFAULT_SIZE
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
        this.usedSize = 0; // 初始化时,顺序表中元素个数为0
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2. 函数实现

# 2.1 display(打印)

打印函数顾名思义就是将顺序表中所有的数据打印出来。打印完的标准就是将顺序表中的数组完全输出,因此用usedSize作为终止条件,

public void display() {
    // 遍历数组中的每个元素,直到usedSize
    for (int i = 0; i < this.usedSize; i++) {
        // 打印当前元素并用空格隔开
        System.out.print(this.elem[i] + " ");
    }
    // 所有元素打印完毕后换行
    System.out.println();
}
1
2
3
4
5
6
7
8
9

# 2.2 add(新增)

add方法是用于向MyArrayList顺序表中添加一个新元素的。这个方法首先检查当前顺序表的存储空间是否已满,如果已满,则进行扩容操作;如果未满,直接将新元素添加到顺序表的末尾。

public void add(int data) {
    // 判断当前数组是否已满,即元素个数等于数组长度
    if (this.usedSize == elem.length) {
        // 如果数组已满,则对数组进行扩容。新数组长度为原数组长度的2倍
        // 使用Arrays.copyOf方法实现数组扩容,并将扩容后的新数组赋值给elem
        this.elem = Arrays.copyOf(elem, elem.length * 2);
    }
    // 在数组未满的情况下,或扩容后,将新数据添加到数组的usedSize位置
    // usedSize表示当前存储的元素个数,同时也指向了下一个可以存放元素的位置
    elem[usedSize] = data;
    // 添加元素后,元素个数usedSize增加1
    usedSize++;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.3 add(指定位置新增)

这个add方法的作用是在MyArrayList顺序表的指定位置pos插入一个新的元素data。这个过程需要考虑几个关键步骤:下标合法性检查、顺序表空间检查、元素后移以及实际插入操作

public void add(int pos, int data) {
    // 检查指定的位置pos是否合法
    // pos的合法范围是0到usedSize,包含0和usedSize,因为可以在末尾添加元素
    if (pos < 0 || pos > usedSize) {
        throw new ArrayIndexOutOfBoundsException("下标非法,请检查");
    }
    // 检查顺序表是否已满
    if (this.usedSize == elem.length) {
        // 如果已满,则进行扩容,新的数组长度为原来的2倍
        this.elem = Arrays.copyOf(elem, elem.length * 2);
    }
    // 将pos位置及之后的元素向后移动一位,为新元素腾出空间
    for (int i = usedSize - 1; i >= pos; i--) {
        elem[i + 1] = elem[i];
    }
    // 在pos位置插入新元素
    elem[pos] = data;
    // 更新顺序表中的元素个数
    usedSize++;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

实现逻辑

  1. 合法性检查:首先检查传入的下标pos是否在合法范围内,即是否在0到usedSize之间。如果不在这个范围内,则抛出ArrayIndexOutOfBoundsException异常,因为插入的位置无效。
  2. 空间检查和扩容:接着,检查顺序表的存储空间是否足够。如果当前存储的元素数量usedSize已经等于数组的长度elem.length,说明数组已满,需要进行扩容。扩容操作通过Arrays.copyOf完成,新数组的长度是原数组长度的2倍。
  3. 元素后移:为了在pos位置插入新元素,需要将pos位置及之后的所有元素向后移动一位。这通过一个从后向前的循环实现,确保在移动元素时不会覆盖未处理的元素。
  4. 插入元素:在腾出的pos位置插入新元素data。
  5. 更新元素计数:完成插入操作后,顺序表的元素个数usedSize增加1。

下面动图演示:

img

# 2.4 contains(包含)

contains方法用于检查MyArrayList顺序表中是否包含特定的值toValue。它通过遍历顺序表中的所有元素,并与toValue进行比较来实现。如果找到一个元素与toValue相等,则方法返回true,表示顺序表包含这个值;如果遍历完所有元素都没有找到相等的值,则方法返回false,表示顺序表不包含这个值。

public boolean contains(int toValue) {
    // 遍历顺序表中的所有元素
    for (int i = 0; i < usedSize; i++) {
        // 检查当前元素是否等于要查找的值toValue
        if (elem[i] == toValue) {
            // 如果找到了一个元素等于toValue,返回true
            return true;
        }
    }
    // 如果遍历完所有元素都没有找到等于toValue的元素,返回false
    return false;
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2.5 indexOf(查找)

indexOf方法用于在MyArrayList顺序表中查找特定值toValue的索引。该方法遍历顺序表中的所有元素,将每个元素与toValue进行比较。如果找到一个元素与toValue相等,则返回该元素的索引。如果遍历完所有元素后没有找到相等的值,则返回-1,表示toValue不在顺序表中。

public int indexOf(int toValue) {
    // 遍历顺序表中的所有元素
    for (int i = 0; i < usedSize; i++) {
        // 检查当前元素是否等于要查找的值toValue
        if (elem[i] == toValue) {
            // 如果找到了一个元素等于toValue,返回该元素的索引i
            return i;
        }
    }
    // 如果遍历完所有元素都没有找到等于toValue的元素,返回-1
    return -1;
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2.6 get(获取指定位置)

get方法用于获取MyArrayList顺序表中指定位置pos的元素值。该方法首先进行下标合法性检查,确保请求的位置在顺序表的有效范围内。如果请求的位置合法,方法则返回该位置的元素值;如果位置不合法,则抛出异常,防止程序访问无效内存区域。

public int get(int pos) {
    // 检查请求的位置pos是否合法
    // pos的合法范围是0到usedSize-1
    // 如果pos小于0或pos大于等于usedSize,说明pos超出了顺序表当前存储元素的范围
    if(pos<0 || pos>=usedSize){
        // 抛出异常,提示位置不合法
        throw new ArrayIndexOutOfBoundsException("下标非法,请查看!");
    }
    // 返回顺序表中pos位置的元素
    // 如果下标合法,则直接返回数组elem中下标为pos的元素
    return elem[pos];
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2.7 set(更新指定位置)

set方法用于更新MyArrayList顺序表中指定位置pos的元素值为value。与获取元素值的操作类似,更新操作之前需要进行下标合法性检查,以确保不会发生数组越界异常。如果给定的位置合法,则将该位置的元素值更新为value。如果位置不合法,则抛出异常。

public void set(int pos, int value) {
    // 检查要更新元素的位置pos是否合法
    // pos的合法范围是0到usedSize-1,确保pos指向顺序表中已存在的元素
    if(pos<0 || pos>=usedSize){
        // 如果pos不在合法范围内,则抛出ArrayIndexOutOfBoundsException异常
        // 异常消息提示"下标错误,请查看!"
        throw new ArrayIndexOutOfBoundsException("下标错误,请查看!");
    }
    // 更新操作:将顺序表中pos位置的元素值更新为value
    // 直接访问数组elem的pos索引位置,然后赋予新的值value
    elem[pos] = value;
}
1
2
3
4
5
6
7
8
9
10
11
12

# 2.8 remove(删除指定key)

remove方法用于从MyArrayList顺序表中删除第一次出现的指定值key。这个过程分为几个步骤:首先,使用indexOf方法查找key在顺序表中的索引;如果找到,则通过覆盖的方式移除该元素,并调整后续元素的位置;最后,更新顺序表的元素计数并将最后一个元素置为默认值(例如0)。如果未找到指定的值,则方法返回false。

public boolean remove(int key) {
    // 使用indexOf方法查找key在顺序表中的索引
    int index = indexOf(key);
    // 如果索引为-1,表示顺序表中没有找到指定的key值
    if (index == -1) {
        System.out.println("没有这个数据");
        return false; // 返回false,表示删除失败
    }
    // 如果找到了指定的key值,开始从index位置开始,将后续元素向前移动一位
    // 这个操作通过循环实现,覆盖index位置的元素,并依次向后移动
    for (int i = index; i < usedSize - 1; i++) {
        elem[i] = elem[i + 1];
    }
    // 完成元素移动后,顺序表的实际元素数量减少1
    usedSize--;
    // 将最后一个元素(现在是无效数据)置为0
    // 这步操作是为了保持数据的整洁,避免保留已删除元素的残留值
    elem[usedSize] = 0;
    // 返回true,表示删除成功
    return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

实现逻辑

  1. 查找要删除的元素索引:首先调用indexOf方法查找key值在顺序表中的索引。如果未找到(indexOf返回-1),则表示顺序表中不存在该值,直接返回false,表示删除操作失败。
  2. 移动元素:如果找到了要删除的元素,则从其位置开始,将所有后续元素向前移动一位,覆盖掉要删除的元素。这通过一个循环实现,直到移动到usedSize - 1位置的元素。
  3. 更新元素数量:移动完元素后,顺序表的usedSize(表示顺序表中元素的数量)减1,以反映一个元素已被删除。
  4. 清理无效数据:为了保持数据的清洁,将现在多余的最后一个元素置为默认值(这里设置为0)。这一步是可选的,主要用于清理可能的残留数据。

下面动图演示:

img

# 2.9 size (长度)

size方法非常直接,它返回MyArrayList顺序表中当前存储的元素个数。这个数量直接对应于内部变量usedSize的值。

public int size() {
    // 返回顺序表当前存储的元素数量,即usedSize的值
    return usedSize;
}
1
2
3
4

# 2.10 clear(清空)

clear方法用于清空MyArrayList顺序表,移除其中的所有元素。在这个简化的模型中,清空操作通过将usedSize置为0来实现。

public void clear() {
    // 将usedSize置为0,逻辑上清空顺序表
    // 之后的任何操作都将基于一个空的顺序表执行
    usedSize = 0;
}
1
2
3
4
5

# 2.11 异常的定义

ArrayIndexException是一个运行时异常,用于表示当程序尝试访问顺序表中非法索引时的错误情况。

public class ArrayIndexException extends RuntimeException {
    // 提供无参数的构造函数
    public ArrayIndexException() {
        super();
    }
 
    // 提供带有错误消息的构造函数
    public ArrayIndexException(String message) {
        super(message); // 调用超类的构造函数,传入错误消息
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 3.测试代码

public class Test {
    public static void main(String[] args) {
        MyArrayList MyArrayList =new MyArrayList();
        //添加数据
        MyArrayList.add(1);
        MyArrayList.add(2);
        MyArrayList.add(3);
        MyArrayList.add(4);
        MyArrayList.add(5);
        //打印
        System.out.print("当前数组元素:");
        MyArrayList.display();
        //值所在的下标
        System.out.print("值所在的下标:");
        System.out.println(MyArrayList.indexOf(3));
        //是否包含这个值
        System.out.print("是否包含这个值:");
        System.out.println(MyArrayList.contains(2));
        //获得下标所在位置元素
        System.out.print("获得下标所在位置元素:");
        System.out.println(MyArrayList.get(3));
        //修改下标的值
        System.out.print("修改下标的值:");
        MyArrayList.set(3,12);
        MyArrayList.display();
        //删除关键字key
        System.out.print("删除关键字key:");
        MyArrayList.remove(2);
        MyArrayList.display();
        //获得长度
        System.out.print("获得当前顺序表长度:");
        System.out.println(MyArrayList.size());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

输出结果如下:

下载 (3)

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
Collections工具类
单向链表的实现

← Collections工具类 单向链表的实现→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式