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

    // 将顺序表的底层容量设置为capacity
    public 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 位置的元素设为 value
    public void set(int pos, int value) {
        try{
            judgePos(pos);
        }catch(Exception e) {
            e.printStackTrace();
            return;
        }
        array[pos]=value;
        }


    //删除第一次出现的关键字key
    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--;
            }
        }
    // 获取顺序表长度
    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,敬请期待! 还希望各位大佬们能给个三连,点点关注,点点赞,发发评论呀,感谢各位大佬~❤️❤️💕💕🥳🎉🎉🎉

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GEE24:合肥市1986-2024年年均NDVI变化分析

代码如下&#xff1a; var roi ee.FeatureCollection("users/yipeizhao736/HefeiProvince"); Map.centerObject(roi); Map.addLayer(roi,{color:grey},roi); // Applies scaling factors. function applyScaleFactors(image) {var opticalBands image.select(SR_B…

如何使用渐变块创建自定义聊天机器人

如何使用渐变块创建自定义聊天机器人 文章目录 如何使用渐变块创建自定义聊天机器人一、介绍二、参考示例1、一个简单的聊天机器人演示2、将流式传输添加到您的聊天机器人3、喜欢/不喜欢聊天消息4、添加 Markdown、图像、音频或视频 一、介绍 **重要提示&#xff1a;**如果您刚…

FloodFill算法简介(用BFS、DFS算法解决)

FloodFill算法中文名&#xff1a;洪水灌溉 FloodFill通常是这样一类问题&#xff0c;如下图&#xff1a; 负数表示凹陷的土地&#xff0c;正数表示凸起的土地&#xff0c;发洪水/下雨会淹没凹陷的地方 通常会问这几种问题&#xff1a; 1.被淹没的区域有几块 2.被淹没的最大…

java的单元测试和反射

单元测试 就是针对最小的功能单元&#xff0c;编写测试代码对其进行正确性测试 Junit单元测试框架&#xff1a; 可以用来对方法进行测试 有点&#xff1a; 可以灵活的编写测试代码&#xff0c;可以针对某个方法进行测试&#xff0c;也支持一键完成对全部方法的自动发测试&a…

Linux中grep详解

一、grep基本介绍 全拼:Global search REgular expression and Print out the line. 从grep的全称中可以了解到&#xff0c;grep是一个可以利用”正则表达式”进行”全局搜索”的工具&#xff0c;grep会在文本文件中按照指定的正则进行全局搜索&#xff0c;并将搜索出的行打印出…

基于工程车辆/物流车辆/消防车辆远程通信的车队管理解决方案

交通运输对全球经济至关重要&#xff0c;特别是长途卡车在现今的供应链中发挥着重要作用。目前&#xff0c;货运物流面临许多挑战&#xff0c;包括不断上升的燃料价格和排放污染等问题。由于重型卡车的尺寸和载重量大&#xff0c;这意味着它们产生更多的二氧化碳排放足迹。在国…

java 溯本求源之基础(十八)之Monitoring--jmc

1.JMC概述 JMC全称Java Mission Control&#xff0c;集成了多个功能强大的组件&#xff0c;其中最核心的两部分是管理控制台和Java Flight Recorder。管理控制台允许开发者实时监控应用的运行状态&#xff0c;捕捉各种性能指标&#xff1b;而Java Flight Recorder则提供了一种高…

SQLite的DBSTAT 虚拟表(三十六)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite运行时可加载扩展(三十五&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 1. 概述 DBSTAT 虚拟表是一个只读的同名虚拟表&#xff0c;返回 有关用于存储内容的磁盘空间量的信息 的 SQLite 数据库。 示例用例…

陈奂仁联手 The Sandbox 推出“Hamsterz Doodles”人物化身系列

全新人物化身系列结合艺术与实用性 开创元宇宙新篇章 著名亚洲唱作歌手兼香港电影金像奖得主陈奂仁携手 The Sandbox&#xff0c;兴奋地宣布推出新的元宇宙人物化身系列 —— Hamsterz Doodles 仓鼠涂鸦。 陈奂仁在 The Sandbox 推出 Hamsterz Doodles 系列&#xff0c;将艺术与…

3i平台体验性能加持,13600KF+B760M+撼与科技A770 TITAN装机体验

在2022年&#xff0c;intel重启显卡线&#xff0c;带来了多款性价比十分不错的显卡。而近段时间&#xff0c;又有传言说intel第二代产品e即将面世&#xff0c;甚至已经有数款Battlemage GPU曝光&#xff0c;让不少intel忠实粉丝直呼期待&#xff0c;或许在今年年底&#xff0c;…

【新知实验室 - TRTC 实践】音视频互动 Demo、即时通信 IM 服务搭建

一、TRTC 初识 TRTC 是什么 TRTC&#xff08;Tencent RTC&#xff09;腾讯实时音视频&#xff0c;源自于 QQ 音视频团队&#xff0c;是基于 QQ 音视频多年来的音视频技术积累&#xff0c;位于腾讯云的 RTC 云服务。TRTC 支持腾讯会议、企业微信直播、微信视频号、腾讯云课堂、…

AI大模型探索之路-实战篇2:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

leetcode最大间距(桶排序+Python)

虽然直接排完序&#xff0c;再求最大差值更快&#xff0c;这里我们还是学一下桶排序。 桶排序主要维护一个bucket&#xff0c;初始bucket【i】 0&#xff0c;遍历nums&#xff0c;当i存在时&#xff0c;令bucket【i】 1&#xff0c;表示存在。遍历完nums&#xff0c;bucket中有…

【点云语义分割】弱监督点云语义分割-双教师指导的对比学习

Weakly Supervised Learning for Point Cloud Semantic Segmentation With Dual Teacher 摘要&#xff1a; 为了增强特征学习能力&#xff0c;我们在这项工作中引入了双教师指导的对比学习框架&#xff0c;用于弱监督点云语义分割。双教师框架可以减少子网络耦合&#xff0c;促…

Java web应用性能分析之服务端慢[网络慢]

Java web应用性能分析之服务端慢&#xff0c;如果是网络原因引起的服务端慢&#xff0c;经常会被忽略&#xff0c;很多时候我们第一时间不会去排查网络原因。出现这种情况也很正常&#xff0c;因为应用的外部网络都是超100M的大宽带服务器&#xff0c;而内部则是千兆网卡或者万…

SpringCloud 与 Dubbo 的区别详解

一、Spring Cloud 和 Dubbo 的概述 1.1 SpringCloud 简介 SpringCloud 是一个用于构建云原生应用的框架集合&#xff0c;它为开发者提供了一套完整的工具链&#xff0c;用于快速搭建分布式系统。SpringCloud 基于 SpringBoot 开发&#xff0c;具有如下特点&#xff1a; 提供…

mysql常见语法操作笔记

1. 数据库的基本操作 1.1. MYSQL登录与退出 D:\phpstudy_pro\Extensions\MySQL5.7.26\bin 输入 mysql -uroot -proot -h127.0.0.1 退出的三种方法 mysql > exit; mysql > quit; mysql > \q; 1.2. MYSQL数据库的一些解释 注意&#xff1a;数据库就相当于文件夹 …

类和对象(2)——封装(封装的概念、包、staic)

前言 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主要研究的就是封装特性。何为封装呢&#xff1f;简单来说就是套壳屏蔽细节。 一、什么是封装 1.1 概念 将数据和操作数据的方法进行有机结合&#xff0c;隐藏对象的属性和实现细节&…

CXL论文阅读笔记整理(持续更新)

CXL 介绍 An Introduction to the Compute Express LinkTM (CXLTM) Interconnect arXiv Paper 对CXL技术进行介绍&#xff0c;包括CXL 1.0、CXL 2.0、CXL 3.0&#xff0c;对各规范的提升做介绍。整理了现有的CXL实现方法&#xff0c;延迟测试结果&#xff0c;对未来发展进行…