ArrayList和顺序表(上)

1. ArrayList的介绍

        在介绍ArrayList之前,我们需要认识一下线性表和顺序表

        线性表: 是n个具有相同特性的数据元素的有限序列.常见的线性表:顺序表,链表,栈,队列...

        线性表在逻辑上是线性结构,也就是一条连续的直线.但是在物理结构上不一定是连续的,线性表在物理上存储的时候,常常以数组和链式结构的形式存储.

        顺序表: 物理地址连续的存储单元组成的线性结构,一般情况用数组来存储.在数组的基础上进行增删查改.总而言之,顺序表就是一个动态扩容的数组.

        ArrayList的简介

        在集合框架里面,ArrayList就是一个普通类,以下是它的具体架构图

        1. ArrayList实现RandomAccess接口,说明ArrayList支持随机访问

        2. ArrayList实现了Cloneable接口,说明ArrayList是可以clone的

        3. ArrayList实现了Serializable接口,说明ArrayList是支持序列化的

        4. ArrayList继承了AbstractList类,这个类又实现了List接口,因此我们可以使用List一系列的方法

        5. ArrayList是泛型类,使用的时候要指定使用的引类型.

2. ArrayList的自我实现

        为了更好的理解ArrayList,我们先不介绍它的方法,我们先模仿它的底层自己实现一下ArrayList.

        2.1 Ilist的创建

    我们模仿ArralList先写一个Ilist接口,里面写了这个接口的抽象方法,以便后续实现类来进行扩充.

以下是Ilist的具体代码

package ArrayList和顺序表.mylist;public interface Ilist {// 新增元素,默认在数组最后新增void add(int data);// 在 pos 位置新增元素void add(int pos, int data);// 判定是否包含某个元素boolean contains(int toFind);// 查找某个元素对应的位置int indexOf(int toFind);// 获取 pos 位置的元素int get(int pos);// 给 pos 位置的元素设为 valuevoid set(int pos, int value);//删除第一次出现的关键字keyvoid remove(int toRemove);// 获取顺序表长度int size();// 清空顺序表void clear();// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的void display();boolean isFull();//判断当前顺序表有没有满boolean isEmpty();//判断是不是空的}

        2.2 MyArrayList的实现

        我们开始写我们自己的ArrayList,取名为MyArrayList.,就像ArrayList一样,我们实现Ilist接口,然后重写里面的方法.

        先介绍以下一些我们自己的变量设定:

        elem是我们创建的数组,我们会在里面进行增删查改

        usedSize是表示有效数据的大小(假设你里面存了4个连续数据,usedSize就为4)

        DEFAULT_SIZE这是一个常量,如果用户没有设定MyArralList的大小,这个常量值就是我们elem数组的默认大小.

        再介绍我们的构造方法,此处我们设定了俩个构造方法,一个有参数一个没参数,有参数的就是用户自己设定数组的大小,没有参数就是把DEFAULT_SIZE常量值设置为默认数组大小.

               

        我们现在来介绍里面具体重写的方法

        1> display()方法: 遍历,打印有效数据

        我们就直接把数组进行遍历,注意我们这里的边界值是usedSize,我们遍历的是有效数据,而不是遍历全部的MyArrayList.

        2> isFull()方法: 判断这个数组的实际长度和有效数据的长度是否相同,如果相同的话,用来作为后续扩容的判断条件.     

        3>  checkCapacity()方法: 这个是用来判断是否需要扩容的方法,判断条件是isFull()方法的返回值,如果确实数据的有效长度和数组的实际长度一样,我们便会使用Arrays.copyOf()方法,对数组进行拷贝,然后长度设为原先的2倍,也就是二倍扩容.(这个方法不是重写的,是我们MyArrayList自己写的)

       4> add(int data)方法 我们在usedSize位置上放置我们新增的数据,在放置的时候,我们需要通过checkCapacity()来对数组容量进行判断,如果是满的就2倍扩容.

     

        5> add(int pos,int data)方法,我们在指定的pos位置上放置数据.这个地方要注意俩个地方,其一:我,们要判断放置的位置的合法性.其二:我们要判断数组的大小是否支持扩容.

        其中我们判断pos的位置,需要写一个checkPoseAdd(pos)方法        

如果pos<0或者pos>usedSize(为什么不取=,是因为add里面的usedSize有扩容机制,不会发生在usedSize下标超出数组界限的情况),如果满足这个情况,我们就抛出一个异常,这个异常是我们自己写的异常,PosIllegality.

         当这些判断都结束,并且没问题,我们就要进行数据的搬运了,因为我们是在指定位置上对数据进行添加,我们就不能单纯的在那个位置上把数据的值赋值过来,这样会覆盖原先数据的值,我们应该把在这个位置上的数据到最后一个数据往后移动一个位置,进行一个整体的搬运才行.

        

        6> contains(int toFind)方法:判断某个元素是不是在这个数组里面,我们需要先判断,我们的数组是不是为空,也就要使用到isEmpyty()方法,如果usedSize == 0那就说明为空.然后我们再遍历整个数组看里面是不是有这个元素,如果有就返回turn.

注意: 如果是查找引用数据类型,一定呀记住重写equals方法

        7> indexOf(int toFind)方法:这个就是返回查找元素的下标,也是先要进行判断,看这个数组是不是空的,再遍历数组,如果找到就返回这个元素的下标.      

        8> get(int pos)方法:获取pos位置下的数据值,这里需要判断我们寻找的下标是不是合法的,并且判断这个数组是不是空的,

判断是否下标合法

这个地方很有意思,因为它和刚刚add里面的判断位置有些不同,就是它甚至把usedSize这个位置也设置成非法位置,这个原因是我们的get方法并没有实现扩容,所以usedSize有可能就会引起下标越界(假设数组长度为5,usedSize也为5,此时我们没有扩容机制,因此,我们如果使用这个下标,就会引起越界)

        判断数组是不是空

        这个里面,如果get到的数组其实是空的,我们就要抛出自己写的异常MyArrayListEmpty,提示一下数组是空的.

        如果上述条件都通过,我们就会直接返回该下标的值

        9> set(int pos,int value)方法:我们设置pos下标的值为value.此处我们需要判断pos位置的合法性,若合法就直接把value值覆盖pos下标的值即可

     

10> remove(int toRemove)方法: 删除这个数据.我们先要判断并找到这个数据的位置,因此要用到indexOf方法,然后我们需要把该位置后面的数据全部整体前移一个位置,把该数据覆盖 

        这里我们设置i的边界是<usedSize-1,而不是<usedSize是因为如果usedSize刚刚好是最后一个元素,后续我们i+1位置就会越界.

        10> size()方法:我们直接返回usedSize大小即可

        11> clear()方法:因为我们现在是操纵的引用数据类型,因此我们直接把usedSize设置为0即可.

        

注意:如果是引用数据类型,我们只是设置为0是不行的,这个会导致内存泄露,JVM只有当对象没有引用的时候才会自动帮我们回收内存,因此我们需要把每一个引用设为null.

        2.3 测试

        我们写一个Test类来对我们自己的MyArrayList进行创建,并且使用里面的方法

结果:

        2.4 整体代码展现

package ArrayList和顺序表.mylist;import java.util.Arrays;public class MyArrayList implements Ilist{//实现Ilist接口,重写所有的方法public int[] elem;public int usedSize;//放一个元素useSize++,usedSize表示有效数据的大小//顺序表的默认大小public static final int DEFAULT_SIZE = 10;//相当于常量public MyArrayList() {this.elem = new int[DEFAULT_SIZE];}//指定大小public MyArrayList(int capacity) {this.elem = new int[capacity];}//遍历,打印有效数据@Overridepublic void display() {//遍历有效数据for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");}System.out.println();}@Overridepublic boolean isFull() {return this.usedSize == this.elem.length;}// 新增元素,默认在数组最后新增@Overridepublic void add(int data) {//如果满了不能放
//        if(isFull()) {
//            //扩容
//           this.elem = Arrays.copyOf(this.elem,this.elem.length*2);//二倍扩容,拷贝数组
//        }我们直接写成一个方法,实现复用//往数组放东西checkCapacity();this.elem[usedSize] = data;usedSize++;}//判断是否需要扩容private void checkCapacity() {if(isFull()) {//扩容this.elem = Arrays.copyOf(this.elem,this.elem.length*2);//二倍扩容,拷贝数组}}// 在 pos 位置新增元素@Overridepublic void add(int pos, int data) {
//        //先检查容量
//        checkCapacity();
//        if (pos < 0 || pos > usedSize) {//
//            System.out.println("不合法!");//自己试一下用异常来搞一下
//            return;
//        }检查pose位置,我们也可以封装复用一下//先需要判断pos的位置try {checkPoseAdd(pos);}catch (PosIllegality e) {e.printStackTrace();return;//因为已经捕获了所以我们后续代码还可以进行,因此需要return直接返回,结束程序}//再看是否需要扩容checkCapacity();//我们移到的地方,如果有元素,我们就要往后移动一下//1.从最后一个有效数据开始往后移动for (int i = usedSize; i >= pos ; i--) {elem[i + 1] = elem[i];}//2.当i < pos 就结束//3.存放元素到pos位置elem[pos] = data;//4.usedSize++usedSize++;}private void checkPoseAdd(int pos) throws PosIllegality{//告诉别人调用这个方法会抛出异常if (pos < 0 || pos > usedSize) {////抛个异常,而不是单纯打印日志throw new PosIllegality("插入元素下标异常: " + pos);}}//判断某个元素是不是在这里面@Overridepublic boolean contains(int toFind) {//先判断是否为空if (isEmpty()) {//如果不判断的话,要是为空,我们还进行下标的访问,就会空指针异常return false;}//不是空的,就遍历数组,看里面是不是有这个元素for (int i = 0; i < usedSize; i++) {//如果是查找引用数据类型,一定记住要重写方法 equalsif(elem[i] == toFind) {return true;//在进行比较的时候,要想清楚,想比较的是地址还是内容}}return false;}public boolean isEmpty() {return usedSize == 0;}
//返回指定位置的下标@Overridepublic int indexOf(int toFind) {//先判断是否为空if (isEmpty()) {return -1;}//不是空的,就遍历数组,看里面是不是有这个元素for (int i = 0; i < usedSize; i++) {//如果是查找引用数据类型,一定记住要重写方法 equalsif(elem[i] == toFind) {return i;//在进行比较的时候,要想清楚,想比较的是地址还是内容}}return -1;}//获取pos 的值@Overridepublic int get(int pos) throws MyArrayListEmpty{//调用这个方法就要抛出异常//看是否在合法下标内获取到checkPoseGetAndSet(pos);//判断这个数组是否是空的if(isEmpty()) {throw new MyArrayListEmpty("获取指定下标元素的时候顺序表为空!");}return elem[pos];}private void checkPoseGetAndSet(int pos) throws PosIllegality{//告诉别人调用这个方法会抛出异常if (pos < 0 || pos >= usedSize) {//add是可以在usedSize位置上添加元素的,相当于在尾巴上面加元素,而get和set,在used//抛个异常,而不是单纯打印日志throw new PosIllegality("获取指定元素下标异常: " + pos);}}//给pos位置修改value@Overridepublic void set(int pos, int value) {checkPoseGetAndSet(pos);elem[pos] = value;}@Overridepublic void remove(int toRemove) {//1.先找到要删除的数据的位置int index = indexOf(toRemove);if(index == -1) {throw new RuntimeException("没有这个元素");//自己创建一个异常}//2.找到之和就把后面一个覆盖前面一个for (int i = index; i < usedSize - 1 ; i++) {//i一定是usedSize-1,因为usedSize在覆盖过程中并没有改变它的大小,所以当搞到最后一个的时候i+1会越界elem[i] = elem[i+1];}//3.usedSize--usedSize--;}@Overridepublic int size() {return this.usedSize;}@Overridepublic void clear() {//如果是基本数据类型this.usedSize = 0;//而如果是引用数据类型,只和上面这么搞,会导致内存泄露//JVM回收算法//1.当前对象没有人引用的时候//elem = null/for(){elem[i] = null;}}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

降噪效果好的头戴式耳机有哪些?四大值得入手的百元降噪耳机盘点

在嘈杂的现代生活中&#xff0c;寻找一片属于自己的宁静空间已成为许多人的追求&#xff0c;头戴式降噪耳机凭借其出色的隔音效果和舒适的佩戴体验&#xff0c;成为了众多消费者的首选&#xff0c; 在通勤路上的喧嚣&#xff0c;还是办公室内的嘈杂&#xff0c;降噪效果好的头…

jmeter在beanshell中使用props.put()方法的注意事项

在jmeter中&#xff0c;通常使用beanshell去处理一些属性的设置和获取的操作&#xff0c;而这些操作也是有一定的规则的。 1. 设置属性时&#xff0c;在属性名上要加双引号&#xff0c;这代表它不是一个需要用var去声明的变量 这种设置属性的方式才是有效可行的&#xff0c;在…

使用HTML、CSS和JavaScript创建图像缩放功能

使用HTML、CSS和JavaScript创建图像缩放功能 在这篇博客文章中&#xff0c;我们将介绍如何使用HTML、CSS和JavaScript创建一个简单的图像缩放功能。这个功能可以增强用户体验&#xff0c;让访问者在点击图像时查看更大的版本。 效果 步骤1&#xff1a;设置HTML结构 首先&…

Pytest基于fixture的参数化及解决乱码问题

我们知道&#xff0c;Pytest是Python技术栈下进行自动化测试的主流测试框架。支持灵活的测试发现、执行策略&#xff0c;强大的Fixture夹具和丰富的插件支持。 除了通过pytest的parametrize标签进行参数化外&#xff0c;我们通过fixture的param参数也可以比较方便地实现参数化…

java对接GPT 快速入门

统一对接GPT服务的Java说明 当前&#xff0c;OpenAI等GPT服务厂商主要提供HTTP接口&#xff0c;这使得大部分Java开发者在接入GPT时缺乏标准化的方法。 为解决这一问题&#xff0c;Spring团队推出了Spring AI &#xff0c;它提供了统一且标准化的接口来对接不同的AI服务提供商…

记一次有趣的发现-绕过堡垒机访问限制

前言 在某一次对设备运维管理的时候&#xff0c;发现的某安全大厂堡垒机设备存在绕过访问限制的问题&#xff0c;可以直接以低权限用户访问多个受控系统&#xff0c;此次发现是纯粹好奇心驱使下做的一个小测试压根没用任何工具。因为涉及到了很多设备和个人信息&#xff0c;所以…

rom定制系列------小米6x_MIUI14_安卓13刷机包修改写入以及功能定制 界面预览

在接待一些定制化系统中。有很多工作室或者一些特殊行业的友友需要在已有固件基础上简略修改其中的功能。方便使用。例如usb调试默认开启。usb安装设置以及usb安装与内置删减一些app的定制服务。今天给友友预览其中小米6X此款机型定制相关的一些界面与功能演示。 定制机型以及…

Web自动化Demo-Go+Selenium

1.新建工程 使用GoLand新建工程如下&#xff1a; 打开终端输入如下命令安装Selenium go get -u github.com/tebeka/selenium 2.编写代码 package mainimport ("fmt""github.com/tebeka/selenium""log""time" )const (chromeDriver…

【AUTOSAR 基础软件】ComM模块详解(通信管理)

文章包含了AUTOSAR基础软件&#xff08;BSW&#xff09;中ComM模块相关的内容详解。本文从AUTOSAR规范解析&#xff0c;ISOLAR-AB配置以及模块相关代码分析三个维度来帮读者清晰的认识和了解ComM这一基础软件模块。文中涉及的ISOLAR-AB配置以及模块相关代码都是依托于ETAS提供的…

2025选题推荐|基于微信小程序的高校就业招聘系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

MFC框架制作的exe,当界面增加或者删除组件后,需要如何修改Dlg.cpp?

使用Microsoft Foundation Classes&#xff08;MFC&#xff09;框架制作的应用程序中&#xff0c;当界面中增加或删除组件后&#xff0c;需要对Dlg.cpp文件进行相应的修改&#xff0c;以确保程序能够正确地初始化和管理这些组件。 1. 更新资源文件 (.rc) 首先&#xff0c;确保你…

Elasticsearch学习笔记(六)使用集群令牌将新加点加入集群

随着业务的增长&#xff0c;陆续会有新的节点需要加入集群。当我们在集群中的某个节点上使用命令生成令牌时会出现报错信息。 # 生成令牌 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s node出现报错信息&#xff1a; Unable to create enrollment…

【React】使用脚手架或Vite包两种方式创建react项目

1.使用脚手架搭建React项目&#xff1a; 在终端窗口运行如下命令即可&#xff1a; npx create-react-app react-basic(创建的文件目录) npx&#xff1a;Node.js工具命令&#xff0c;用于查找并执行后续的包命令。 2.使用Vite包创建React项目&#xff1a; 在终端窗口运行如…

Redis集群相关

目录 一、Redis主从集群 主从数据同步原理 全量同步 1&#xff09;为什么是基本一致而不是完全一致呢&#xff1f; 2&#xff09;上述过程还有一个问题&#xff0c;怎么判断是不是第一次同步&#xff1f; 增量同步 1&#xff09;master节点怎么知道slave节点与自己的数据…

初学者如何快速入门人工智能

一、引言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;&#xff0c;作为当今科技领域极具前景与影响力的方向之一&#xff0c;吸引着众多人士投身其中。无论是对科技充满好奇的学生&#xff0c;还是意图拓展职业发展路径的职场人士&#xff0c…

STM32 USB CUBEMX

开发背景 使用的平台&#xff1a;STM32H750 注意事项 时钟必须是48MHZ&#xff0c;其它都不行 2. 将默认任务的堆栈设大一点 如果使用操作系统&#xff0c;USB任务跑在默认任务里&#xff0c;因此需要设置默认任务的堆栈缓存是直接定义的全局变量&#xff0c;需要设置编译器…

Spring Boot常见错误与解决方法

White graces&#xff1a;个人主页 &#x1f649;专栏推荐:Java入门知识&#x1f649; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; ⛳️点赞 ☀️收藏⭐️关注&#x1f4ac;卑微小博主&#x1f64f; 目录 创建第一个SpringBoot项目 SpringBoot项目各个…

基于神经协同过滤(Neural Collaborative Filtering,NCF)的算法

论文题目&#xff1a;Neural Collaborative Filtering∗ 论文地址&#xff1a;https://arxiv.org/abs/1708.05031 今天我要分享一篇关于深度学习在推荐系统中应用的经典论文&#xff0c;题为“基于神经协同过滤&#xff08;Neural Collaborative Filtering&#xff0c;NCF&…

如何去除背景音乐保留人声?保留人声,消除杂音

在日常生活和工作中&#xff0c;我们经常遇到需要处理音频的情况&#xff0c;尤其是当我们想要去除背景音乐&#xff0c;仅保留人声时。这种需求在处理电影片段、制作音乐MV、或者提取演讲内容等场景中尤为常见。本文将为您详细介绍如何去除背景音乐并保留人声&#xff0c;帮助…

组合式API有什么好处

什么是组合式API&#xff1f; 组合式 API (Composition API) 是一系列 API &#xff08;响应式API、生命周期钩子、依赖注入&#xff09;的集合。它不是函数式编程&#xff0c;组合式 API 是以 Vue 中数据可变的、细粒度的响应性系统为基础的&#xff0c;而函数式编程通常强调…