【Java 数据结构】ArrayList的实现和底层源码讲解

news2025/7/6 17:28:59

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习!

欢迎志同道合的朋友一起加油喔🦾🦾🦾
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个🐒嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心


目录

一. 模拟实现ArrayList​编辑

1.定义顺序顺序表

2. 函数实现

(1) 打印顺序表display()函数

(2) 新增元素函数add() (默认在数组最后新增)

(3) 在 pos 位置新增元素add()函数(与上方函数构成重载)

(4) 判定是否包含某个元素contains()函数

(5) 查找某个元素对应位置indexOf() 函数

(6) 获取pos位置的元素get()函数

(7) 将pos位置的元素更新为value set()函数

(8) 删除第一个关键字key remove()函数

(9) 获得顺序表的长度size()函数

(10) 清空顺序表clear()函数

 (11) 异常的定义:

3.测试代码

二. ArrayList底层的扩容机制

三.顺序表的优缺点



 顺序表本质上就是一个数组,而顺序表就是实现对这个数组进行增删查改等操作方法的一个类,而Java中也有类似与顺序表的集合类:ArrayList<E> 下面我会对这个类里面比较重要且常用的方法进行实现。

一. 模拟实现ArrayList

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

1.定义顺序顺序表

public class MyArrayList{
 
    public int[] elem;
    public int usedSize;//目前存储元素个数
    //默认容量
    private static final int DEFAULT_SIZE = 10;
 
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
}

上方定义类SeqList即是顺序表,定义elem数组存储数据,定义usedSize表示当前数组中包含多少个元素,定义DEFAULT_SIZE值为了在构造方法中将顺序表初始化为DEFAULT_SIZE大小的数组。

2. 函数实现

(1) 打印顺序表display()函数

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

public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(elem[i]+" ");
        }
        System.out.println();
    }

(2) 新增元素函数add() (默认在数组最后新增)

此函数是增加顺序表中元素的函数。增加元素时,有一点需要注意,你的顺序表是否含有空间放入新的元素。使用函数isFull()判断,若没有满就正常增加,若已满,先对顺序表扩容,再进行增加

 如何判断顺序表满没满?当数组的长度等于数组中包含元素就为满。

当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。

public void add(int data) {
        if (this.usedSize == elem.length) {
            this.elem = Arrays.copyOf(elem, elem.length * 2;
        }
        elem[usedSize] = data;
        usedSize++;
    }

(3) 在 pos 位置新增元素add()函数(与上方函数构成重载)

我们要判断传过来的下标的合法性;分析pos的取值范围:我们要把新增函数放到现在已有元素之间,因此我们可以知道,pos的范围应该是 0<=pos<usedSize.若给定的下标不合法,我们就抛出一个异常,让程序停下来。

再者这个函数功能也是添加,因此我们也需要判断顺序表空间的问题。

若我们插入的位置已有元素,我们需把从pos位置的元素向后移,为data数据挪开位置。

当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。

public void add(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            throw new ArrayIndexException("下标非法,请检查");
        }
        if (this.usedSize == elem.length) {
            this.elem = Arrays.copyOf(elem, elem.length * 2;
        }
        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }

 下面动图演示:

(4) 判定是否包含某个元素contains()函数

 拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回true,否则返回false。

public boolean contains(int toValue) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toValue) {
                return true;
            }
        }
        return false;
    }

(5) 查找某个元素对应位置indexOf() 函数

同上方思想一致,拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回下标i,否则返回-1。

public int indexOf(int toValue) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toValue) {
                return i;
            }
        }
        return -1;
    }

(6) 获取pos位置的元素get()函数

我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。

public int get(int pos) {
        if(pos<0||pos>=usedSize){
            throw new ArrayIndexException("下标非法,请查看!");
        }
        return elem[pos];
    }

(7) 将pos位置的元素更新为value set()函数

同上方一样,我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。最后将value赋到pos位置

public void set(int pos, int value) {
        if(pos<0||pos>=usedSize){
            throw new ArrayIndexException("下标错误,请查看!");
        }
        elem[pos] = value;
    }

(8) 删除第一个关键字key remove()函数

我们先调用indexOf()函数,判断顺序表中是否有我们删除的值,若有找到这个值的下标,没有就返回false。有就以覆盖的方式,将index下标的元素用他后一个元素覆盖,一直往复到最后一个元素,因为删除了一个元素,所以将usedSize减一,因为在覆盖时,最后一个元素是无效数据所以没有覆盖,我们将他置为0。

public boolean remove(int key) {
        int index = indexOf(key);
        if (index == -1) {
            System.out.println("没有这个数据");
            return false;
        }
        for (int i = index; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
        elem[usedSize] = 0;
        return true;
    }

 下面动图演示:

(9) 获得顺序表的长度size()函数

当前数组中包含多少个元素,顺序表就是多长,因此顺序表的长度就是usedSize的大小。

public int size() {
        return usedSize;
    }

(10) 清空顺序表clear()函数

因为所有的函数都是围绕这usedSisz进行构造的,我们只需将usedSize置为0,其他函数就无法进行运行(此处并非范例)

public void clear() {
        usedSize = 0;
    }

 (11) 异常的定义:

public class ArrayIndexException extends RuntimeException{
 
 
        public ArrayIndexException() {
        }
 
        public ArrayIndexException(String message) {
            super(message);
        }
}

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

输出结果如下: 


二. ArrayList底层的扩容机制

ArrayList是一个动态类型的顺序表,即在插入元素的时候会自动扩容,下面是扩容机制:

🕯️总结:

✨当使用无参的构造方法创建ArrayList,容量默认值10在第一次插入的时候才会初始化初始容量,而不是在创建的时候就初始化容量

✨在插入时,会检测是否真正需要扩容,如果需要,调用grow扩容

✨初步预估按照原容量的1.5倍扩容
✨如果用户所需大小超过预估的1.5倍,则按照用户所需大小扩容
✨真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

✨使用copyOf进行扩容 

三.顺序表的优缺点

 顺序表也是分情况使用的,如何判断呢?总结了它的优缺点,可以作为参考。

  优点:

  1. 无需为表示表中元素之间的逻辑关系而增加额外的存储空间。
  2. 可以快速地获取表中任意位置的元素。

  缺点:

  1. 插入和删除操作需要移动大量元素(时间复杂度高)。
  2. 当线性表长度变化较大时,难以确定存储空间的容量。
  3. 造成存储空间的“碎片”。(当我们添加元素时,例如我们有101个元素,数组初始大小为100,扩容为1.5倍,初始大小无法存储全部元素,因此需要扩容,扩容为150大小,这就浪费了49个空间)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java day9

第九章 使用swing 9.1 创建应用程序9.1.1 创建页面9.1.2 开发框架9.1.3 创建组件&& 9.1.4 将组件加入到容器中 9.2 使用组件9.2.1 图标9.2.2 标签9.2.3 文本框9.2.4 文本区域9.2.5 可滚动窗格9.2.6 复选框和单选按钮9.2.7 组合框9.2.8 列表 9.1 创建应用程序 import j…

FPGA基于SFP光口实现10G万兆网UDP通信 10G Ethernet Subsystem替代网络PHY芯片 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案4、vivado工程详解5、上板调试验证并演示6、福利&#xff1a;工程代码的获取 1、前言 目前网上的fpga实现udp基本生态如下&#xff1a; 1&#xff1a;verilog编写的udp收发器&#xff0c;但不带ping功能&#xff0c;这样的代…

The GNU nano text editor (文本编辑器)

The GNU nano text editor (文本编辑器) https://www.nano-editor.org/ GNU nano is a small and friendly text editor. 1 GNU nano The GNU nano text editor https://www.nano-editor.org/dist/latest/nano.html Source Code https://git.savannah.gnu.org/cgit/nano.gi…

EIGRP 配置,详解拓扑表,路由汇聚

1.3 EIGRP 拓扑&#xff0c;路由以及汇聚 1.3.1 实验目的 通过对 EIGRP 拓扑&#xff0c;路由以及汇聚相关实验的练习&#xff0c;掌握 EIGRP 建立拓扑信息的方式&#xff0c; 度量计算方法&#xff0c;如何调整度量&#xff0c;非等价负载均衡&#xff0c;以及 EIGRP 末节路…

anaconda ( jupyter notebook ) 安装 Cartopy库

文章目录 一、Cartopy库是什么&#xff1f;二、一步到位安装&#xff08;装不上的话用下面那个方法虚拟环境安装&#xff09;三、如何在anaconda ( jupyter notebook ) 虚拟环境安装 Cartopy库&#xff1f; 一、Cartopy库是什么&#xff1f; Cartopy 是一个开源免费的第三方 P…

mac压缩文件多了__MACOSX目录问题

文章目录 背景原因解决方案&#xff1a;更换压缩方式分析问题拓展&#xff08;.DS_Store&#xff09; 背景 项目中有一个场景&#xff0c;需要把目录压缩为app离线包的zip 但是压缩之后一致打不开&#xff0c;别人上传的zip是好的 原因 如图&#xff0c;我上传的在安卓设备…

D.8零样本文本分类应用:基于UTC的医疗意图分类,打通数据标注-模型训练-模型调优-预测部署全流程。

NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…

如何制作 ChatGPT 清晰有效咒语与Chat GPT高效交流——基础篇 第二课

在上一篇文章中&#xff0c;我们已经了解了 ChatGPT 的特性、应用范围以及逆天之处。然而&#xff0c;要想获得 ChatGPT 的逆天能力&#xff0c;最关键的一点就是必须掌握准确的“咒语”&#xff0c;即让其能够准确地理解我们所说的话&#xff0c;以及我们想要的东西。本篇文章…

一条记录的多幅面孔-事务的隔离级别与 MVCC

一、事务隔离级别 引出&#xff1a;**事务的隔离性要求&#xff0c;**理论上在某个事务对某个数据进行访问时&#xff0c;其他事务应该进行排队&#xff0c;当该事务提交之后&#xff0c;其他事务才可以继续访问这个数据。我们既想保持事务的 隔离性 &#xff0c;又想让服务器…

CCED,落下帷幕,国产新型编辑技术的锋芒,终于露出来了

大家还记得在DOS时代&#xff0c;你们常用的办公软件有哪些吗&#xff1f; 想必一定少不了朱崇君的CCED和求伯君的WPS吧&#xff0c;前者是字表处理&#xff0c;后者是文字处理。在DOS时代&#xff0c;这两个软件用起来真的是得心应手啊。 而这个时代&#xff0c;也成为了CCE…

jupyter中的魔法函数

在jupyter中&#xff0c;使用魔法函数可以简单的实现一些单纯python要很麻烦才能实现的功能。 1. % 行魔法函数&#xff0c;只对本行代码生效。 2. %% Cell魔法函数&#xff0c;在整个Cell中生效&#xff0c;必须放于Cell首行。 3. %lsmagic&#xff1a; 列出所有的魔法函数 4…

Android Gradle —— flavorDimensions 与 productFlavors

参考&#xff1a; Android Gradle&#xff08;3&#xff09;— FlavorDimensions_积跬步_图腾的博客-CSDN博客 flavorDimensions和productFlavors——安卓gradle_猛猛的小盆友的博客-CSDN博客 多维度打包的介绍 flavorDimensions 从单词字面理解知道是 “风味维度”&#xf…

jsp小练习01--jdbc小练习01

目录 jsp小练习01 jdbc小练习01 设计数据库 以下是一个基本的登录页面&#xff08;login.jsp&#xff09;&#xff1a; 以下是checklogin.jsp页面的示例代码&#xff1a; 以下是main.jsp页面的示例代码&#xff1a; 以下是add.jsp页面的示例代码&#xff1a; 以下是doa…

【2023 · CANN训练营第一季】昇腾AI入门课(Pytorch)——第三章 AI应用开发

第1节 课程概述 第1单元 本课程是否适合您 1.没有深度学习的背景 边学习边补充基础 2.少量深度学习背景&#xff0c;但并不了解华为昇腾 对于昇腾的学习是贯穿全程的 3.听说过或接触过华为昇腾&#xff0c;但不知道如何基于昇腾使能AI应用。 保持学习&#xff0c;按时交作业…

Letcode 两数之和

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以…

Wi-Fi 6(802.11ax)解析12:下行OFDMA接入机制(DL-OFDMA)

序言 在介绍完802.11ax的信道接入以及其触发帧机制后&#xff0c;本文着重介绍下行OFDMA的接入机制&#xff08;即DL-OFDMA&#xff09; 下行OFDMA接入机制&#xff08;DL-OFDMA&#xff09; OFDMA是一种多用户通信机制&#xff0c;其只适用于802.11ax AP和802.11ax用户之间…

ChatGPT 学习 ES lucene 底层写入原理,源码

一直有个疑问“学习最新版lucene 数据写入相关的源码&#xff0c;应该看哪些源码&#xff0c;以什么顺序看&#xff08;先看什么&#xff0c;后看什么&#xff09;&#xff1f;” 对于Lucene的数据写入过程&#xff0c;可以分为以下几个阶段 在学习Lucene的数据写入相关的源码…

FTP服务

一、FTP的简介 FTP是FileTransferProtocol&#xff08;文件传输协议&#xff09;的英文简称&#xff0c;而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时&#xff0c;它也是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的…

C++笔记——第十四篇 哈希

目录 一、unordered系列关联式容器 1.1 unordered_map 1.1.1 unordered_map的文档介绍 1.1.2 unordered_map的接口说明 二、 底层结构 2.1 哈希概念 2.2 哈希冲突 2.3 哈希函数 2.4 哈希冲突解决 2.4.1 闭散列 1. 线性探测 2. 二次探测 2.4.2 开散列 三、 哈希的应用 …

200万奖金广聚天下算法英雄,第二届广州·琶洲算法大赛要来了!

随着深度学习不断驱动技术创新&#xff0c;人工智能加速与实体经济深度融合发展。作为中国首个自主研发、开源开放的产业级深度学习平台&#xff0c;飞桨与百度自研的产业级知识增强文心大模型&#xff0c;共同构筑了产业智能化基座&#xff0c;并联合产学研用各方生态力量&…