【Java数据结构】初步认识ArrayList与顺序表

前言~🥳🎉🎉🎉   

hellohello~,大家好💕💕,这里是E绵绵呀✋✋ ,如果觉得这篇文章还不错的话还请点赞❤️❤️收藏💞 💞 关注💥💥,如果发现这篇文章有问题的话,欢迎各位评论留言指正,大家一起加油!一起chin up!👍👍 

💥个人主页:E绵绵的博客
💥所属专栏:JAVA知识点专栏   JAVA题目练习  c语言知识点专栏   c语言题目练习

❤️❤️这篇文章我们就正式开始数据结构的学习,学习其中的顺序表结构。出发吧!

参考文章:Java【顺序表】详细图解模拟实现 + 【ArrayList】常用方法介绍_java顺序表逻辑图-CSDN博客

线性表 

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列...

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

顺序表 

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 并且顺序表是一个动态数组,可以存储不同的元素,还可以根据需要自动调整大小。

顺序表的模拟实现

❤️❤️为什么要模拟实现:
自己模拟实现 简易版的 顺序表的增删查改等主要功能,大致理解顺序表的设计思想
再对比学习 Java 提供的集合类当中的 ArrayList ,在学习 Java 的 ArrayList 常用方法的同时,也能学习源码的思想。

成员属性 

Java 中的 ArrayList(顺序表) 是集合框架中的一个类,要模拟实现顺序表,也得自己实现一个类,首先要考虑这个类中的成员属性。

之前就已经说过,顺序表底层是基于数组实现的,那么成员属性就需要:
1️⃣数组 array:来存放数据
2️⃣变量 capacity :来记录数组的容量,当数组中的存放的数据满了就需要增大容量
3️⃣变量 useSize:来记录数组已经存放了几个数据

❤️❤️为了体现封装思想,成员属性全部设置为 private

public class SeqList {private int[] array;// 数组private int capacity;// 容量private int useSize;// 当前数组存放的数据的个数
}

⚠️顺序表的模拟实现重在理解理想,为了简便,我们不使用泛型🙅,数组中存放 int 类型

成员方法 

❤️❤️如下是模拟顺序表的成员方法,我们通过这些成员方法来模拟顺序表的功能,我们现在来一一实现这些方法。

// 新增元素,默认在数组最后新增
public void add(int data) { }// 在 pos 位置新增元素
public void add(int pos, int data) { }// 判定是否包含某个元素
public boolean contains(int toFind) { return true; }// 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }// 获取 pos 位置的元素
public int get(int pos) { return -1; }// 给 pos 位置的元素设为 value
public void set(int pos, int value) { }//删除第一次出现的关键字key
public void remove(int toRemove) { }// 获取顺序表长度
public int size() { return 0; }// 清空顺序表
public void clear() { }// 打印顺序表,注意:ArrayList 没有这个方法,为了方便看测试结果给出的
public void display() { }

1.构造方法

 构造方法的作用:初始化成员属性,useSize 无需初始化,编译器默认初始化为 0

    // 将顺序表的底层容量设置为capacitypublic SeqList(int capacity){this.capacity = capacity;// 为数组开辟内存空间 this.array = new int[this.capacity];}
    public SeqList() {this.capacity=10;this.array=new int[10];//当无参数时,默认创建一个为容量为10的数组}

 2,add——新增元素,默认在数组末尾新增

❗️❗️在末尾新增数据之前,必须考虑:顺序表是否已🈵️,如果满了,则需要扩容之后再添加元素 。

所以我们需要分别写出 判满 和 扩容 这两个方法:


 2.1, isFull——判断顺序表是否已满 
    public boolean isFull() {return this.useSize == this.capacity;}

  2.2, expandCapacity——扩容
  public  void expandCapacity(){this.array =Arrays.copyOf(this.array,capacity*2);capacity*=2;}
}

利用 copyOf 方法,拷贝数组并将新数组容量扩大两倍,让 this.array 引用新的数组。


 ✅所以 add 方法的写法为: 

    public void add(int data) {// 判满if (isFull()) {// 满了就扩容expandCapacity();}this.array[this.useSize] = data;this.useSize++;}

最后记得,增加数据之后,**useSize 也要++**❗️❗️ 


3.add——在 pos 位置新增元素

 ❗️❗️这个方法是:在指定位置新增元素,新增之前必须考虑:
1️⃣顺序表是否已满
2️⃣pos 位置是否合法

3.1, judgeAddPos——判断 add 时pos 位置合法性
判满的方法以及写过了,现在我们需要补充: 判断 pos 位置合法性 的方法
需要思考,pos 在什么位置才是合法呢? 

这就要提一个知识点了:在数据结构中,我们每次往一个数据结构里存储数据时,该数据必须有一个前驱信息(前驱是指该元素的前一个元素),否则不能存放。

所以我们举个例子,如下:

像该情况我们的pos自然不能小于0,而又因为数组中存储数据时,该数据必须要有前驱信息,所以不能大于3。所以pos不能小于0或大于3.


所以在这我们可以得出以下代码

public void judgeAddPos(int pos){if(pos<0||pos>useSize){throw new ArrayListIndexOutOfException("pos位置不合法");}}
}

如果 pos 参数不合法,就不能执行下面的代码,抛出一个异常,所以我们可以自定义一个异常类

// 继承于运行时异常
public class ArrayListIndexOutOfException extends RuntimeException {public ArrayListIndexOutOfException(String str) {super(str);}
}

这样,当我们 add 时的 pos 参数不合法时,就会抛出异常。

“准备工作” 做足之后,我们需要考虑,如何实现在 pos 位置新增,也就是如何去插入?

🚗🚗🚗
就是把 pos 下标以及之后 的数据 向后依次 覆盖,最终把 pos 位置“空出来”,放入新数据:

 

  public void add(int pos, int data) {try{judgeAddPos(pos);}catch(Exception e){e.printStackTrace();return;}if(isFull()){expandCapacity();}for (int i = useSize-1; i >pos-1 ; i--) {array[i+1]=array[i];}array[pos]=data;useSize++;}

我们之所以在这用try-catch是为了防止出现这个错误后就直接导致程序崩溃,运行不了后面的程序,所以我们用try-catch捕获它,就能在发生这个错误后依然能运行这个程序。


⚠️注意:
要先移动 3,再移动 2 ——从后往前的顺序移动
如果先移动 2 ,则会把 3 覆盖掉,丢失数据。

最后不要忘记 useSzie++ ❗️❗️

4.contains——判定是否包含某个元素

比较简单,遍历整个数组即可

public boolean contains(int toFind) {for (int i = 0; i <useSize ; i++) {if(array[useSize]==toFind)return  true;}return false;}

因为这里我们存放的是 int 类型的变量,但 ArrayList 当中可以存放引用数据类型的
⚠️⚠️⚠️当表中是引用类型时,就不可以用“等号”比较,应该用 equals 方法

5, indexOf——查找某个元素对应的位置 

还是遍历数组,不过这里如果没找到该元素,则要抛出异常,我们上面讲过类似的,这里就不重复讲了 。在这我们又自定义了一个异常类。

class  NotFindPos extends RuntimeException{public  NotFindPos(String message){super(message);}
}
    public int indexOf(int toFind) {for (int i = 0; i <useSize ; i++) {if(array[i]==toFind)return i;}try{throw  new NotFindPos("不存在该数"+toFind);   }catch (Exception e){return -1;}}

因为这里我们存放的是 int 类型的变量,但 ArrayList 当中可以存放引用数据类型的
⚠️⚠️⚠️当表中是引用类型时,就不可以用“等号”比较,应该用 equals 方法

6.get——获取 pos 位置的元素 

在获取 pos 之前必须保证 pos 位置合法性,但此时的 pos 判断合法性和 add 时的判断规则不一样❗️❗️


🚗🚗🚗
获取 pos 位置的元素,前提是 pos 位置上有数据
此时 pos 的合法性判断规则是:pos 不能小于 0 或 不能大于 useSize - 1

 6.1,judgePos——判断 pos 位置合法性
    public  void judgePos(int pos){if(pos<0||pos>useSize-1){throw new ArrayListIndexOutOfException("pos位置不合法");}
}}

如果pos 不合法,抛出异常❌

  做好 “准备工作” 之后, get 方法就很简单了

  public int get(int pos) {try {judgePos(pos);} catch (Exception e) {e.printStackTrace();return -1;}return array[pos];
}

 7, set——给 pos 位置的元素设为 value

老规矩,pos 作为参数时,就要判断合法性❗️❗️代码很简单。

 public void set(int pos, int value) {try{judgePos(pos);}catch(Exception e) {e.printStackTrace();return;}array[pos]=value;}

8,remove——删除第一次出现的数据 

我们前面分析过了 add 方法的执行原理,那么删除的原理恰好是和 add 的操作相反:在数组中要 “删除” 一个数,让后面的数据依次向前覆盖即可,对于这个删除操作,我们在图书管理器中碰见过相同的操作,其是一样的思路。 

可以看到最后还剩一个 3,没有必要处理,useSize- - 即可✅
别忘了,怎么找到待删除数据的位置呢❓——调用前面写过的 indexOf 方法❗️

    public void remove(int toRemove) {int pos = indexOf(toRemove);if (pos == -1) {// 找不到的情况System.out.println("不存在该数据");}else {// 注意这里的循环条件for (int i = pos; i < this.useSize - 1; i++) {this.array[i] = this.array[i + 1];}this.useSize--;}}

  ⚠️注意:
 i < this.useSize - 1 这里不能写成 <=,当数组正好是满的情况下
 this.array[i] = this.array[i + 1]; 这里访问 i+1 下标就会数组越界

9,size——获取顺序表长度 

直接返回 useSize 即可 

public int size() {return useSize;}

10.clear——清空顺序表 

因为该数组存放的内容为基本类型,所以我们只需要将usesize变为0就行。

    public void clear() {this.useSize = 0;}

如果存放的是引用类型,不仅要将useSize变为0,还要将数组中存放的引用变量指向的空间全释放掉。释放掉的方法就是将数组存放的引用变量全指向null,当这些空间没有引用变量指向时,就会自动释放掉。

之所以要释放这些空间是为了防止内存泄漏,提高空间的利用率。


ArrayList类中的clear方法就是一个很好的例子,如下:(因为其数组存放的是引用变量)

11,display——打印顺序表 

注意:顺序表中不存在该方法,我们这是为了方便看测试结果自己加的。

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

 ArrayList的模拟实现总代码

import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;public class SeqList {private int[] array;// 数组private int capacity;// 容量private int useSize;// 当前数组存放的数据的个数public SeqList(int capacity) {this.capacity = capacity;this.array = new int[this.capacity];}public SeqList() {this.capacity = 10;this.array = new int[10];//当无参数时,默认创建一个为容量为10的数组}// 新增元素,默认在数组最后新增public void add(int data) {// 判满if (isFull()) {// 满了就扩容expandCapacity();}this.array[this.useSize] = data;this.useSize++;}// 在 pos 位置新增元素public void add(int pos, int data) {try {judgeAddPos(pos);} catch (Exception e) {e.printStackTrace();return;}if (isFull()) {expandCapacity();}for (int i = useSize - 1; i > pos - 1; i--) {array[i + 1] = array[i];}array[pos] = data;useSize++;}// 判定是否包含某个元素public boolean contains(int toFind) {for (int i = 0; i < useSize; i++) {if (array[useSize] == toFind)return true;}return false;}// 查找某个元素对应的位置public int indexOf(int toFind) {for (int i = 0; i < useSize; i++) {if (array[i] == toFind)return i;}try {throw new NotFindPos("不存在该数" + toFind);} catch (Exception e) {e.printStackTrace();return -1;}}// 获取 pos 位置的元素public int get(int pos) {try {judgePos(pos);} catch (Exception e) {e.printStackTrace();return -1;}return array[pos];
}// 给 pos 位置的元素设为 valuepublic void set(int pos, int value) {try{judgePos(pos);}catch(Exception e) {e.printStackTrace();return;}array[pos]=value;}//删除第一次出现的关键字keypublic void remove(int toRemove) {int pos = indexOf(toRemove);if (pos == -1) {// 找不到的情况System.out.println("不存在该数据");}else {// 注意这里的循环条件for (int i = pos; i < this.useSize - 1; i++) {this.array[i] = this.array[i + 1];}this.useSize--;}}// 获取顺序表长度public int size() {return useSize;}// 清空顺序表public void clear() {useSize=0;}// 打印顺序表,注意:ArrayList 没有这个方法,为了方便看测试结果给出的public void display() {for (int i = 0; i <useSize ; i++) {System.out.print(array[i]+" ");}System.out.println();}public boolean isFull() {return  this.capacity == this.useSize;}public  void expandCapacity(){this.array =Arrays.copyOf(this.array,capacity*2);capacity*=2;}public void judgeAddPos(int pos){if(pos<0||pos>useSize){throw new ArrayListIndexOutOfException("pos位置不合法");}}public  void judgePos(int pos){if(pos<0||pos>useSize-1){throw new ArrayListIndexOutOfException("pos位置不合法");}
}}class  ArrayListIndexOutOfException extends  RuntimeException{public ArrayListIndexOutOfException(String message) {super(message);}
}
class  NotFindPos extends RuntimeException{public  NotFindPos(String message){super(message);}
}

 模拟的顺序表SeqList的使用

class Test{public static void main(String[] args) {SeqList seqList=new SeqList();seqList.add(0,4);seqList.add(1);seqList.add(4);seqList.display();seqList.remove(1);seqList.display();seqList.clear();seqList.add(1);seqList.display();seqList.add(5);System.out.println(seqList.contains(5));seqList.set(1,6);seqList.display();System.out.println(seqList.contains(5));System.out.println(seqList.indexOf(2));System.out.println(seqList.get(0));seqList.set(4,3);seqList.add(2,7);seqList.display();System.out.println(seqList.size());}}

对于其打印如下:


❤️❤️我们看显示结果可知这代码的确没问题。所以对于这模拟的顺序表我们就模拟成功了.你们自己也可以使用下该代码,看下是否有误,如果有误欢迎大佬来评论区指点一下。

 总结

所以这就是我们的顺序表第一部分内容,我们在这主要对顺序表进行了模拟,使我们在之后的学习中能更加理解顺序表的源码,学习其源码思想。在之后的顺序表第二部分我们将给大家介绍真正的顺序表ArrayList,敬请期待! 还希望各位大佬们能给个三连,点点关注,点点赞,发发评论呀,感谢各位大佬~❤️❤️💕💕🥳🎉🎉🎉

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

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

相关文章

分布式文件系统--MinIO

1 MinIO安装(Docker) ●在root目录下新建docker_minio文件夹 ●在docker_minio文件夹下新建config文件夹,data文件夹 ●在root目录下新建docker_compose文件夹,在docker_compose文件夹中添加docker-compose.yaml services:minio:image: quay.io/minio/miniocontainer_name: mi…

Vuforia AR篇(三)— AR模型出场效果

目录 前言一、AR模型出场二、AR出场特效三、添加过渡效果四、效果 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内容。 一、AR模型出场 创建ARCamer…

Three.js——基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

【树莓派】强力烧写工具 Balena Etcher,烧写树莓派系统,树莓派系统克隆,备份

文章目录 使用Win32DiskImager备份和写入树莓派系统步骤一&#xff1a;下载和安装Win32DiskImager步骤二&#xff1a;准备工作步骤三&#xff1a;备份树莓派系统步骤四&#xff1a;写入树莓派系统 使用Balena Etcher给树莓派烧写系统Balena Etcher简介步骤一&#xff1a;下载Ba…

Mac安装telnet

一、安装Homebrew 1、打开官网&#xff1a;Homebrew — The Missing Package Manager for macOS (or Linux) 2、打开终端输入&#xff1a; /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 二、安装Telnet bre…

【LAMMPS学习】八、基础知识(4.5)TIP5P水模型

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

园区智慧化转型新篇章:解码智慧技术如何助力园区实现精细化管理,提升运营效率

目录 一、智慧技术概述及其在园区管理中的应用 &#xff08;一&#xff09;物联网技术的应用 &#xff08;二&#xff09;大数据技术的应用 &#xff08;三&#xff09;云计算技术的应用 二、智慧技术助力园区实现精细化管理 &#xff08;一&#xff09;实现资源优化配置…

轻松上手,无缝对接:详述如何接入企讯通空号检测接口API

企讯通空号检测接口API作为一款高效、精准的手机号码状态检测工具&#xff0c;能够帮助企业及开发者快速识别手机号码的有效性&#xff0c;优化通讯资源&#xff0c;提升营销效果。本篇文章将带领您一步步了解如何轻松、无缝地对接企讯通空号检测接口API&#xff0c;让您的业务…

【RAG 论文】Adaptive-RAG:自适应地根据 query 难度来选择合适的 RAG 模型

论文&#xff1a;Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity ⭐⭐⭐⭐ Code&#xff1a;github.com/starsuzi/Adaptive-RAG NAACL 2024&#xff0c;arXiv:2403.14403 文章目录 一、论文速读二、实现细节2.1 三种…

使用FPGA实现逐级进位加法器

介绍 逐级进位加法器就是将上一位的输出作为下一位的进位输入&#xff0c;依次这样相加。下面以一个8位逐级进位加法器给大家展示。 我增加了电路结构&#xff0c;应该很容易理解吧。 下面我也列举了一位加法器&#xff0c;可以看下。 电路结构 设计文件 1位加法器 librar…

Docker 的数据管理 端口映射 容器互联 镜像的创建

目录 概念 概念 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。总结&#xff1a;因为容器数据是临时保存的为了安全&#xff0c;就要让数据保持持久化。 1&#…

OceanBase单机版安装体验

前情提要 上周OceanBase开发者大会过后&#xff0c;作为观察员也来体验一下OB的安装。业内有某个国产安装用了两周&#xff0c;这种其实有点劝退了。话说就是10年前&#xff0c;没搞过Oracle的人也不用两周安装一个数据库啊。今天看看OB的&#xff08;一体化&#xff09;安装。…

计算机网络----第十三天

DNS协议和文件传输协议 DNS&#xff1a; 含义&#xff1a;用于域名和IP地址的互相解析 DNS域名&#xff1a; 背景&#xff1a;通过IP地址访问目标主机&#xff0c;不便于记忆 域名的树形层次化结构&#xff1a; ①根域 ②顶级域&#xff1a;主机所处的国家/区域&#xf…

一纸歉文难挽人心,特步站在了“悬崖边”

撰稿|多客 来源|贝多财经 日前&#xff0c;一场马拉松赛事风波把特步推上了舆论风口。 此次事件说起来也并不复杂&#xff0c;在4月14日举办的2024北京半程马拉松赛最后冲刺的几百米&#xff0c;几位外籍选手在超过何杰后&#xff0c;对何杰做出回头看、摆手示意的动作&…

谁是存储器市场下一个“宠儿”?

AI浪潮对存储器提出了更高要求&#xff0c;高容量、高性能存储产品重要性正不断凸显&#xff0c;存储产业技术与产能之争也因此愈演愈烈&#xff1a;NAND Flash领域&#xff0c;闪存堆叠层数持续提升&#xff1b;DRAM领域HBM持续扩产&#xff0c;技术不断迭代&#xff0c;同时3…

Spring 5源码学习

文章目录 一. 访问[spring官网], 找到Spring Framework&#xff0c;点击红色标记github仓库&#xff0c;下载对应的分支代码&#xff0c;本人下载5.1.x二. 安装gradle三. 调整spring-framework配置四. 开始编译五.导入idea 一. 访问[spring官网], 找到Spring Framework&#xf…

【STM32+HAL+Proteus】系列学习教程---ADC(查询、中断、DMA模式下的电压采集)

实现目标 1、学会STM32CubeMX软件关于ADC的配置 2、掌握ADC三种模式&#xff08;查询、中断、DMA&#xff09;编程 3、具体目标&#xff1a;1、将开发板单片机采集到的电压值上传至上位机串口调试助手显示。 一、ADC 概述 1、什么是ADC? ADC&#xff08;Analog to Digit…

【课程发布】软考高项目十大管理ITTO宫殿记忆法新版第四版正式发布

软考高项十大管理ITTO宫殿记忆法视频课程&#xff1a; 平台&#xff1a;荔枝微课 连接&#xff1a;十方教育 各位软考高级信息系统项目管理师考生好&#xff0c;新版第四版十大管理ITTO宫殿记忆法视频课程终于发布了&#xff0c;之前苦等的考生终于迎来了救星&#xff0c;再也…

浅谈数据模型

1&#xff1a;事实表和维表的概述 前言&#xff1a;数据仓库是一种用于存储和管理大量数据的技术。其中&#xff0c;事实表和维表是数据仓库中的两个重要概念&#xff0c;首先了解一下事实表和维度表 1.事实表&#xff1a;是指用于存储测量“事实数据”的表&#xff0c;事实数…

算法学习笔记Day8——回溯算法

本文解决几个问题&#xff1a; 回溯算法是什么&#xff1f;解决回溯算法相关的问题有什么技巧&#xff1f;回溯算法代码是否有规律可循&#xff1f; 一、介绍 1.回溯算法是什么&#xff1f; 回溯算法就是个多叉树的遍历问题&#xff0c;关键在于在前序和后序时间点做一些操作…