ArrayList与顺序表(1)

前言~🥳🎉🎉🎉   

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/diannao/1771.shtml

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

相关文章

【苍穹外卖】HttpClient-快速理解入门

目录 HttpClient-快速理解&入门1. 需求2. 如何使用3. 具体示例4. 大致优点5. 大致缺点 HttpClient-快速理解&入门 1. 需求 在平常访问服务器里面的资源的时候&#xff0c;我们通常是通过浏览器输入网址&#xff08;或者在浏览器点击某个连接&#xff09;这种方式&…

测试的分类(2)

目录 按照执行方式分类 静态测试 动态测试 按照测试方法 灰盒测试 按照测试阶段分类 单元测试 集成测试 系统测试 冒烟测试 回归测试 按照执行方式分类 静态测试 所谓静态测试就是不实际运行被测软件,只是静态地检查程序代码, 界面或文档中可能存在错误的过程. 不以…

ffmpeg安装使用(详细)

目录结构 前言ffmpeg下载ffmpeg环境变量配置ffmpeg环境变量配置验证ffmpeg使用举例说明.mp4 转 .wav.mp3 转 .wav.ogg 转 .wav 参考链接 前言 本文主要记录ffmpeg在Windows系统中的安装使用方法。 ffmpeg下载 FFmpeg官网下载 ffmpeg环境变量配置 解压后将“.\ffmpeg\bin”…

vscode 如何断点调试ros1工程

在vscode中断点调试ros1工程主要分为以下几步&#xff1a; 1. 第一步就是修改cmakelist.txt&#xff0c;到调试模式。 将CMAKE_BUILD_TYPE原来对应的代码注释掉&#xff0c;原来的一般都不是调试模式。加上下面一行代码&#xff0c;意思是设置调试模式。 # 断点调试 SET(CMAK…

【Linux】文件基本属性

Linux 系统是一种典型的多用户系统&#xff0c;不同的用户处于不同的地位&#xff0c;拥有不同的权限。 为了保护系统的安全性&#xff0c;Linux 系统对不同的用户访问同一文件&#xff08;包括目录文件&#xff09;的权限做了不同的规定。 在 Linux 中我们可以使用 ll 或者 …

《你想活出怎样的人生》上映,AOC带你打开宫崎骏的动画世界大门!

摘要&#xff1a;宫崎骏式美学&#xff0c;每一帧都是治愈&#xff01; 近日&#xff0c;宫崎骏新作《你想活出怎样的人生》正式公映。苍鹭与少年的冒险、奇幻瑰丽的场景、爱与成长的主题&#xff0c;让观众们收获到满满的爱与感动。宫崎骏总能以细腻的画面、温柔的音乐&#…

设计模式——模板方法

1)模板方法模式(Template Method Pattem)&#xff0c;又叫模板模式(Template Patern)&#xff0c;在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现&#xff0c;但调用将以抽象类中定义的方式进行。 2)简单说&#xff0c;模板方法模式 定义一个操作中…

ETLCloud中多并行分支运行的设计技巧

在大数据处理领域&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;流程是至关重要的一环&#xff0c;它涉及数据的提取、转换和加载&#xff0c;以确保数据的质量和可用性。而在ETL流程中&#xff0c;多并行分支的运行设计是一项关键技巧&#xff0c;可以有效…

华为ensp中MSTP多网段传输协议(原理及配置命令)

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月22日15点29分 在华为ENSP中&#xff0c;MSTP&#xff08;多段传输协议&#xff09;是重要的生成树协议&#xff0c;它扩展了STP&#xff08;生成树协议&#xff09…

猴子摘桃问题(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int sum 1;int i 0;//运算&#xff1b;for (i 1; i < 10; i){//运算&#xff1b;sum …

typecho博客的相对地址实现

typecho其中的博客地址,必须写上绝对地址,否则在迁移网址的时候会出现问题,例如页面记载异常 修改其中的 typecho\var\Widget\Options\General.php 中的165行左右, /** 站点地址 */if (!defined(__TYPECHO_SITE_URL__)) {$siteUrl new Form\Element\Text(siteUrl,null,$this-…

怎么把3d模型旋转加复制---模大狮模型网

在3D设计中&#xff0c;旋转和复制模型是常见且重要的操作&#xff0c;它们可以帮助设计师创建复杂的场景并节省时间。本文将介绍如何在3D建模软件中旋转并复制模型&#xff0c;以及一些技巧和注意事项&#xff0c;帮助您轻松实现这些操作。 旋转3D模型&#xff1a; 旋转3D模型…

心理学|变态心理学健康心理学——躯体疾病患者的一般心理特点

一、对客观世界和自身价值的态度发生改变 患者除了内部器官有器质或功能障碍外&#xff0c;他们的自我感觉和整个精神状态也会发生变化。使人改变对周围事物的感受和态度&#xff0c;也可以改变患者对自身存在价值的态度。这种主观态度的改变&#xff0c;可以使患者把自己置于人…

PaddleSeg开始与搭建

因为使用的比较多,所以来总结一下。 先介绍一下,为什么用PaddleSeg 1、搭建模型更容易,和MMSeg相比,配置更加简单,容易上手 缺点是 1、目前版本还无法生成热力图,我看Paddle官方已经出比赛在解决这个问题了 2、和主流pytorch存在一定差别,模型迁移时需要熟悉两种配置;M…

BFS解决FloodFill算法:(Leetcode:200. 岛屿数量)

题目链接&#xff1a;200. 岛屿数量 - 力扣&#xff08;LeetCode&#xff09; 本题由于没有给出开始搜索的位置&#xff0c;所以每一个位置都要进行一次广度优先搜索 另外为了不修改原数组数据&#xff0c;需要设置一个bool类型的二维数组vis来判断某个位置是否被搜索过 cl…

Numpy方法总结(二)

一. 高级索引 相比于基本索引&#xff0c;高级索引可以访问到数组中的任意元素&#xff0c;并且可以用来对数组进行复杂的操作和修改。 1.整数数组索引 整数数组索引是指使用一个数组来访问另一个数组的元素。这个数组中的每个元素都是目标数组中某个维度上的索引值。 示例…

MapReduce——ReudceTask并行度决定机制

MapReduce——ReudceTask并行度决定机制 1. Reduce任务的数量&#xff08;reduce task count&#xff09;&#xff1a; 这是最基本的决定因素之一。在作业启动时&#xff0c;用户可以指定Reduce任务的数量。更多的Reduce任务意味着更多的并行度&#xff0c;因为每个Reduce任务…

150G全国1米分辨率土地利用数据【2023年】

#1数据摘要 全国1米分辨率土地利用数据 全国范围,分省份分类,1米精度土地利用数据。2023年版本。 数据格式:tif 坐标系:wgs1984 范围:全国各省份 时间:2023年 精度:1米 地类:共计11个地类 中国1m分辨率土地覆盖数据 文件命名与介绍:数据为GeoTIFF栅格格式,每个城市…

Excel 公式的定义、语法和应用(LOOKUP 函数、HLOOKUP 函数、VLOOKUP 函数;MODE.MULT 函数; ROUND 函数)

一、公式的定义和语法 二、公式的应用 附录 查找Excel公式使用方法的官方工具【强烈推荐!!!】:Excel 函数(按字母顺序)【微软官网】 excel 函数说明语法LOOKUP 函数在向量或数组中查找值LOOKUP(lookup_value, lookup_vector, [result_vector])

Webfunny前端监控如何接入飞书单点登录(SSO)

Hello&#xff0c;大家好&#xff0c;欢迎使用**webfunny前端监控和埋点平台**。今天我们将介绍一下如何接入飞书的登录系统。 友情提示&#xff1a;如果飞书侧已经配置好了&#xff0c;可以直接跳到第六步阅读。 一、创建飞书网页项目 进入飞书开发者后台&#xff0c;创建企…