数据结构之ArrayList与顺序表(上)
找往期文章包括但不限于本期文章中不懂的知识点:
个人主页:我要学编程(ಥ_ಥ)-CSDN博客
所属专栏:数据结构(Java版)
顺序表的学习,点我
上面这篇博文是关于顺序表的基础知识,以及顺序表的实现。
目录
手动实现顺序表的源码:
分析Java 8 的 ArrayList 的源码
字段:
构造方法:
ArrayList本身的扩容机制和分配内存机制
ArrayList常见操作
ArrayList的遍历
普通for循环遍历
for-each遍历
toString方法遍历
迭代器遍历
手动实现顺序表的源码:
下面是Java版的顺序表源码:
public class MyArraylist {public int[] elem;public int usedSize;//0//默认容量private static final int DEFAULT_SIZE = 10;public MyArraylist() {this.elem = new int[DEFAULT_SIZE];}/*** 打印顺序表:* 根据usedSize判断即可*/public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i]+" ");}System.out.println();}// 新增元素,默认在数组最后新增public void add(int data) {// 增加元素之前得先判断数组是否已满if (isFull()) {expansion();}// 尾插数据不需要判断 pos 位置是否合法elem[this.usedSize++] = data;}// 扩容private void expansion() {// 原来数组的2倍扩容this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);}/*** 判断当前的顺序表是不是满的!* @return true:满 false代表空*/public boolean isFull() {// 判断这个数组的有效元素个数是否等于数组的长度return this.usedSize == this.elem.length;}private boolean checkPosInAdd(int pos) {if (pos < 0 || pos > this.usedSize) {return false;}return true;//合法}// 在 pos 位置新增元素public void add(int pos, int data) throws PosofAddException{if (!checkPosInAdd(pos)) {throw new PosofAddException("add(int pos, int data) " +"pos位置不合法");}// 判断是否为尾插if (pos == this.usedSize) {add(data);}else {// 开始移除元素(从后往前移除)for (int i = this.usedSize; i > pos; i--) {this.elem[i] = this.elem[i-1];}// 开始插入数据this.elem[pos] = data;this.usedSize++;}}// 判定是否包含某个元素public boolean contains(int toFind) {// 先判断这个数组是否有元素if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}// 查找某个元素对应的位置public int indexOf(int toFind) {for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}// 获取 pos 位置的元素public int get(int pos) throws PosofGetException{if (pos < 0 || pos > this.usedSize) {throw new PosofGetException("get(int pos)" +"pos位置不合法");}return this.elem[pos];}private boolean isEmpty() {// 有效数据个数为0,就是为空return this.usedSize == 0;}// 给 pos 位置的元素设为【更新为】 valuepublic void set(int pos, int value) throws PosofSetException{// 先得判断这个 pos 位置是否合法if (pos < 0 || pos >= this.usedSize) {throw new PosofSetException("set(int pos, int value)" +"要修改的位置不合法");}this.elem[pos] = value;}/*** 删除第一次出现的关键字key* @param key*/public void remove(int key) throws PosofRemoveException{int pos = indexOf(key); // 下标if (pos < 0) {throw new PosofRemoveException("remove(int key)" +"没有您要删除的数据");}for (int i = pos; i < this.usedSize - 1; i++) {// 后一个位置往前覆盖this.elem[i] = this.elem[i+1];}this.usedSize--;}// 获取顺序表长度public int size() {return this.usedSize;}// 清空顺序表public void clear() {// 由于存放的是基本数据类型,直接清空即可this.usedSize = 0;// 如果存放的是引用数据类型就得通过for循环遍历把数组的内容置为null// 注意:如果直接把数组置为null的话,就会存在安全问题,而且源码也是遍历的方式}
}
异常:
PosofAddException:
public class PosofAddException extends RuntimeException{public PosofAddException() {}public PosofAddException(String msg) {super(msg);}
}
PosofGetException:
public class PosofGetException extends RuntimeException{public PosofGetException() {}public PosofGetException(String msg) {super(msg);}
}
PosofSetException:
public class PosofSetException extends RuntimeException{public PosofSetException() {}public PosofSetException(String msg) {super(msg);}
}
PosofRemoveException:
public class PosofRemoveException extends RuntimeException{public PosofRemoveException() {}public PosofRemoveException(String msg) {super(msg);}
}
分析Java 8 的 ArrayList 的源码
实现了咱们自己写的顺序表了之后,就该来看Java本身的源码是怎么写的以及与我们的有什么不同?(注意:由于Java 17封装性太强,不好观看源码,因此下面的源码来自Java 8。)
字段:
elementData 就是我们自己实现的 elem 数组。
size 就是 usedSize ,也就是这个数组的有效元素的个数。
构造方法:
Java 8 实现的顺序表有三个构造方法。
带有一个 int 类型的参数的构造方法:
不带参数的构造方法:
带一个 Collection 类型的参数的构造方法:
下面的是其源码:
首先,我们得知道Collection 到底是这个啥?
根据上面这个图可以得知:Collection 是一个接口。
上面的参数先不看泛型,那就是Collection c 这个意味着只要实现了Collection 接口,就可以被当成实参传过来。而从上图的关系可知:ArrayList 继承了 AbstractLIst 这个抽象类 ,并且实现了LIst这个接口,而 LIst 这个接口拓展了 Collection 这个接口的功能。也就意味着 ArrayList 这个类实现了 Collection 这个接口。那么 ArrayList 就可以被当成参数传过来。
接下来,就是了解 <? extends E> ,?就可以当成是被传过来的 ArrayList 中的泛型,也就是说被传过来的 ArrayList 中的泛型要是 E 或者 E的子类。例如:
了解了这些,我们就来看源码吧。这个源码的大概意思是把传入的 ArrayList 中的元素给全部拷贝到原来的 ArrayList 的后面。
ArrayList本身的扩容机制和分配内存机制
既然我们在创建一个顺序表的时候,原本是空,那么当我们去增加元素的时候,扩容的机制又是如何呢?
上面是分析过程(可忽略),总之,得出了下面这个结论:
当顺序表为空时,我们如果去增加元素,就会初始化一个大小10的数组。并且数组在满了之后,会按照1.5倍的扩容方式来扩容。如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容。
ArrayList常见操作
boolean add(E e) | 尾插e |
void add(int index, E element) | 将 e 插入到 index 位置 |
boolean addAll(Collection<? extends E> c) | 将c 中的元素进行尾插 |
E remove(int index) | 删除 index 位置元素 |
boolean remove(Object o) | 删除遇到的第一个o |
E get(int index) | 获取下标index位置元素 |
E set(int index, E element) | 将下标 index 位置元素改为 element |
void clear() | 清空 |
boolean contains(Object o) | 判断是否在顺序表中 |
int indexOf(Object o) | 返回第一个o所在下标 |
int lastlndexOf(Object o) | 返回最后一个o的下标 |
List<E> subList(int fromlndex, int tolndex) | 截取部分list |
大部分方法,我们都很熟悉。因此这里只展示 addAll()方法 和 subList 方法。
addAll () 方法可以实现 ArrayList 的带Collection 类型的参数的构造方法。
从上面打印的结果可以看出来,ArrayList 是重写了toString 方法的。
从这里我们就可以看出来,被分割的数组应该是下面这样:
ArrayList的遍历
普通for循环遍历
public class Test {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);for (int i = 0; i < arrayList.size(); i++) {System.out.print(arrayList.get(i)+" ");}}
}
for-each遍历
public class Test {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);for (Integer x : arrayList) {System.out.print(x+" ");}}
}
toString方法遍历
public class Test {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);System.out.println(arrayList.toString());}
}
迭代器遍历
public class Test {public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);// 调用iterator方法生成一个迭代器,用Iterator<E>来接收Iterator<Integer> integerIterator = arrayList.iterator();// 如果下一个元素有值话,就进入while循环,并且打印下一个值,最后自己往后走while (integerIterator.hasNext()) {System.out.print(integerIterator.next()+" ");}}
}
只要是实现了 Iterator 接口就可以使用迭代器的方式来遍历。就是下面这张图:
好啦!本期 数据结构之ArrayList与顺序表(上)的学习就到此结束啦!我们下一期再一起学习吧!
相关文章:

数据结构之ArrayList与顺序表(上)
找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:数据结构(Java版) 顺序表的学习,点我 上面这篇博文是关于顺序表的基础知识,以及顺序表的实现。…...

Java 8 中的 Stream API,用于处理集合数据
Java 8 引入了 Stream API,使得处理集合数据变得更加简洁和高效。Stream API 允许开发者以声明式编程风格操作数据集合,而不是使用传统的迭代和条件语句。 一、基本概念 1.1 什么是 Stream Stream 是 Java 8 中的一个新抽象,它允许对集合数…...

106、python-第四阶段-3-设计模式-单例模式
不是单例类,如下: class StrTools():pass str1StrTools() str2StrTools() print(str1) print(str2) 运用单例,先创建一个test.py class StrTools():pass str1StrTools()然后创建一个hello.py,在这个文件中引用test.py中的对象&a…...

【猫狗识别系统】图像识别Python+TensorFlow+卷积神经网络算法+人工智能深度学习
猫狗识别系统。通过TensorFlow搭建MobileNetV2轻量级卷积神经算法网络模型,通过对猫狗的图片数据集进行训练,得到一个进度较高的H5格式的模型文件。然后使用Django框架搭建了一个Web网页端可视化操作界面。实现用户上传一张图片识别其名称。 一、前言 …...

记录汇川:红绿灯与HMI-ST
项目要求: 子程序: 子程序: 实际动作如下: 红绿灯与HMI-ST...

已解决java.nio.charset.CoderMalfunctionError: 编码器故障错误的正确解决方法,亲测有效!!!
已解决java.nio.charset.CoderMalfunctionError: 编码器故障错误的正确解决方法,亲测有效!!! 亲测有效 报错问题解决思路解决方法1. 检查和清理输入数据2. 选择正确的字符集3. 处理异常情况4. 更新Java版本或库5. 检查第三方库的依…...

Linux 中常用的设置、工具和操作
1.设置固定的ip地址步骤 1.1 添加IPADDR“所设置的固定ip地址” TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FAILURE_FATAL"no" IPV6INIT"yes" IPV6…...

[论文笔记]AIOS: LLM Agent Operating System
引言 这是一篇有意思的论文AIOS: LLM Agent Operating System,把LLM智能体(代理)看成是操作系统。 基于大语言模型(LLMs)的智能代理的集成和部署过程中存在着许多挑战,其中问题包括代理请求在LLM上的次优调度和资源分配,代理和LLM之间在交互…...
2024全国高考作文题解读(文心一言 4.0版本)
新课标I卷 阅读下面的材料,根据要求写作。(60分) 随着互联网的普及、人工智能的应用,越来越多的问题能很快得到答案。那么,我们的问题是否会越来越少? 以上材料引发了你怎样的联想和思考?请写…...

【功能超全】基于OpenCV车牌识别停车场管理系统软件开发【含python源码+PyqtUI界面+功能详解】-车牌识别python 深度学习实战项目
车牌识别基础功能演示 摘要:车牌识别系统(Vehicle License Plate Recognition,VLPR) 是指能够检测到受监控路面的车辆并自动提取车辆牌照信息(含汉字字符、英文字母、阿拉伯数字及号牌颜色)进行处理的技术。车牌识别是现代智能交通…...

TESSENT2024.1安装
一、安装过程参考Calibre安装过程(此处省略,不再赘述) 二、安装license管理器: SiemensLicenseServer_v2.2.1.0_Lnx64_x86-64.bin 三、Patch补丁: tessent安装目录和license管理安装目录,执行FlexNetLic…...
【机器学习】原理与应用场景 Python代码展现
机器学习:原理、应用与实例深度解析 引言一、机器学习的基本原理二、机器学习的应用范围三、机器学习实例解析四、机器学习部分讲解五、机器学习的挑战与未来 引言 随着大数据和计算能力的飞速发展,机器学习(Machine Learning, ML࿰…...
Python怎么循环计数:深入解析与实践
Python怎么循环计数:深入解析与实践 在Python编程中,循环计数是一项基础且重要的技能。无论是处理列表、遍历文件,还是执行重复任务,循环计数都发挥着不可或缺的作用。本文将从四个方面、五个方面、六个方面和七个方面详细阐述Py…...

Facebook企业户 | Facebook公共主页经营
Facebook作为社交媒体巨头,拥有庞大的用户基数,因此,有效经营公共主页是获取持续流量、提升客户信任度和粘性、促进产品或服务销售与转化的关键。要优化Facebook主页,关注以下几点: 1、参与度是关键指标:因…...

排序数组 ---- 分治-归并
题目链接 题目: 分析: 用这道题来回顾一下归并排序的思想找到中间结点, 将数组分成两半, 运用递归的思想, 继续对一半进行分半, 分到最后剩一个元素, 再将左右数组合并, 合并两个有序数组, 是先分解, 再合并的过程在合并两个有序数组时, 需要一个额外的数组来记录, 为了避免每…...

【红黑树变色+旋转】
文章目录 一. 红黑树规则二. 情况一叔叔存在且为红情况二.变色旋旋 一. 红黑树规则 对于红黑树,进行变色旋转处理,终究都是为了维持颜色以下几条规则,只有颜色和规则维持住了,红黑树就维持住了最长路径的长度不超过最短路径的两倍…...
pytorch 使用tensor混合:进行index操作
(Pdb) tmp torch.randn(3,5) (Pdb) indx torch.tensor([1,0]).long() (Pdb) temp(indx) *** NameError: name ‘temp’ is not defined (Pdb) tmp(indx) *** TypeError: ‘Tensor’ object is not callable (Pdb) tmp[indx] tensor([[ 0.1633, 0.9389, 1.2806, -0.2525, 0.28…...

Threejs(WebGL)绘制线段优化:Shader修改gl.LINES模式为gl.LINE_STRIP
目录 背景 思路 Threejs实现 记录每条线的点数 封装原始裁剪索引数据 封装合并几何体的缓冲数据:由裁剪索引组成的 IntArray 守住该有的线段! 修改顶点着色器 修改片元着色器 完整代码 WebGL实现类似功能(简易版,便于测…...

继承-进阶
父子类成员共享 普通成员对象/父子间不共享, 成员独立 函数成员共享(函数不存储在对象中) 子类由两部分构成:父类中继承的成员和子类中新定义成员 继承方式 子类中存在父类private成员但不可直接访问(及时在类中&am…...

探索k8s集群的配置资源(secret和configmap)
目录 ConfigMap ConfigMap(主要是将配置目录或者文件挂载到k8s里面使用) 与Secret类似,区别在于ConfigMap保存的是不需要加密配置的信息。(例如:配置文件) ConfigMap 功能在 Kubernetes1.2 版本中引入&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...