值得思索的:ArrayList和线性表,你确定错过这次机会

news2024/11/24 1:47:32

线性表:

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

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

顺序表的大致画图:

 链表的大致画图:

 顺序表:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成 数据的增删查改。

顺序表接口的实现:

    private int[] array;
    private int size;

    // 默认构造方法
    SeqList(){ }

    // 将顺序表的底层容量设置为initcapacity
    SeqList(int initcapacity){ }

    // 新增元素,默认在数组最后新增
    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() { }

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() { }

对于上述的接口,想必让大家看,肯定干看也看不懂多少,所以,笔者来带领大家用一个代码来实现一下!!!相信大家跟着代码,一定会可以实现自主敲写滴!!

话不多说,请看实现顺序表的接口的代码:根据上面的简介,我们可以看出,顺序表的底层是一个数组,因此,我们可以定义一个数组来实现顺序表!!

public class MyArraylist {
    public int[] elem; //该数组在定义的时候,初始状态下默认为null
    public int usedSize;//记录存储了多少个数据
    public static final int DEFAULT_SIZE =5;//定义数组的长度
    
    public MyArraylist(){
        this.elem=new int[DEFAULT_SIZE];//定义数组的长度
    }
}

上述代码,是我们多需要进行的前提准备!!那么,有了这些,我们将可以进行后续的实现顺序表的各个接口了!!

1.   打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的

对于这个的实现,是笔者自己加上去的主要还是为了能够更好的观察结果的运行!!

那么请看笔者的代码;

 // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            //usedSize是数组存储的有效数字
            System.out.print(this.elem[i]+" ");
        }
        System.out.println();
    }

这样我们就可以实现对顺序表的打印了!!
2.获取顺序表长度

对于顺序表的长度,其实我们用usedSize在存储数据的时候,有意识的来统计一下,最后返回就行了!!

 //获取顺序表长度
    public int size () {
        return usedSize;  //usedSize是存储的有效数据
    }

上面两个是最简单的方法了!!那么在后面将会进行深入下去了!!请各位笔者多多思考哟!!

3. 判定是否包含某个元素

对于这个问题,想必大家在之前的解题过程中,就已经有了自己的独特的思维了!那么请看笔者自己的想法吧!!

    // 判定是否包含某个元素
    public boolean contains (int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i]==toFind) {
                return true;
            }
        }
        return false;
    }

笔者写的上述代码的时间复杂度为O(N)  ,我们必须要遍历一遍才行,不管顺序表中含有几个想要寻找的元素,只要有了就可以!!

在上述代码中,我们用了 “==” ,因为我们使用的是整型(int)类型的数组来进行演示的,当我们用其他类型的数组(如,引用类型)那么,就需要使用equals这个来进行比较了!!返回值是false/true,但是,想必会有很多的粉丝想必会选择ComparaTo这个来进行比较吧!但是,在这里不行,因为ComparaTo这个方法的返回值类型为整型的-1,0,1,而我们在本方法中定义的返回值类型为boolean,所以不符合要求!!

4.查找某个元素对应的位置

需要注意的是,我们使用该方法一般返回的是第一次出现的位置!!

    //查找某个元素对应的位置
    public int indefOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
        //返回-1,是因为数组中没有负数下标
    }

这个方法的使用情况跟3. 判定是否包含某个元素相类似,因此,笔者便不再进行解析了!!有问题的话,大家可以看一些=下上面的解析!!

5.新增元素,默认在数组最后新增

新增元素??我们是否需要判断是否在新增之前数组就已经存储满了呢??若是没有就……否则就……因此,我们需要首先对数组进行判断!!

5.(1)判断数组是否已经存储满了??

   //判断数组是否已经存储满了??
    public boolean isFull() {
        //方法1
        if (this.usedSize==this.elem.length) {
            return true;
        }
        return false;

        //方法2:
        //return this.usedSize==this.elem.length;
    }

上述笔者所写的两个方法都能实现:判断数组是否已经存储满了的目的!!其实也是很简单的,主要部分还是在:this.usedSize==this.elem.length 这段代码中!!this.usedSize是用来统计数组中存储多少数据的!而this.elem.length,则可以得出数组的长度!!如果这两个相等,那么数组肯定存储满了,就需要扩容了!

5.(2)扩容

  //扩容
    private void resize() {
        this.elem= Arrays.copyOf(this.elem,2*this.elem.length);
        //实现数组扩容,并且将扩容好的重新赋值给elem
    }

在实现数组扩容的这个方法中,我们用了copyOf()这个方法!对于这个方法不明白的各位老铁,可以看一下copyOf()的底层实现的源码:

5(2).1看一下copyOf()方法的底层实现源码:

   public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

根据上述copyOf()方法,我们可以看出来;copyOf()实现了,将一个数组:int[] original扩容为一个新的长度:int newLength 最后的返回值类型为:int[] ,理解了源码的实现逻辑,因此,我们就可以使用了!

5.(3)根据上述两个方法来实现:新增元素

    //新增元素,默认在数组最后新增
    public void add(int data) {
        if (this.isFull()) {  //判断数组是否已经存储满了??
            resize();//扩容
        }
        this.elem[this.usedSize]=data;//数组的下标从0开始!
        this.usedSize++;
    }

对于上述实现新增元素,涉及到了判断数组是否存储满了,并且实现对数组的扩容,在这两个作为前提的情况下,才能进行后续的新增元素!!当我们新增元素之后,不能忘记对usedSize++ 这样才能准确的得出新增元素之后的长度!!

6.在 pos 位置新增元素

注意,我们所说的是:在 pos 位置新增元素,这就要求我们对其余元素实现依次后移!

在我们进行思考这个题目的时候,需要想到,想要插入的位置,是否大于数组的长度呢??(在数组的长度之外??或者为负数(-1)数组中没有定义负数的下标!!),但是,当放在数组的最后一个位置的时候,数组是否存储满了??是否需要进行扩容处理??这些都是我们需要进行思考的问题!!

6(1)在实现这个在 pos 位置新增元素目的的情况下笔者重新定义了一个类IndexoutOfException.java在这个类中,抛出了异常!

总体抛异常的代码为;

public class IndexoutOfException extends RuntimeException{
    public IndexoutOfException() {

    }

    public IndexoutOfException(String msg) {
        super(msg);
    }
//重写构造方法!!
}

6(2)因此,基于抛异常的这个实现逻辑:我们可以进行下面的代码:

    //在 pos 位置新增元素  时间复杂度为O(N)
    public void add(int pos , int data) {
        checkIndex(pos);//首先要检查pos的位置是否合法??
        if (isFull()) {  //判断数组是否存储满了??
            resize();//扩容
        }
        for (int i = usedSize-1; i >= pos; i--) {
            elem[i+1] = elem[i];
        }
        elem[pos] =data;
        usedSize++;
    }

具体的解析为:

6(3) 检查pos的位置是否合法?

   //检查add数据的时候,判断pos是否合法??
    private void checkIndex(int pos) {
        if (pos <0 || pos >=usedSize)
        throw new IndexoutOfException("get获取元素的时候,位置不合法!请检查位置的合法性!!");
        //当pos的位置不合法的时候,抛出异常!!
    }

对于该部分的简单详见为;

基于上面的三部分,我们才能实现对在 pos 位置新增元素的任务!!其实在其中的一丢丢的细小的情节,希望各位读者能够仔细参考一下!!比如在进行移动数据的时候,一点边缘线的取值!希望大家仔细注意!

7.获取 pos 位置的元素

对于该目的的实现,想必大家参考之前两个方法的实现,已经有着自己的想法了吧!!那么笔者便不再多言了!!一切皆在代码中:

  //获取 pos 位置的元素
    public int get(int pos) {
        checkIndex(pos);//检查pos的合法性!
        return elem[pos];
    }

根据检查pos位置的合法性而来的代码,显得就是很简单了!!但是,里面的逻辑思维还是很重要的!!请大家多多思考!

8. 给 pos 位置的元素设为 value

注意,我们这个的要求是给 pos 位置的元素设为 value,而不是在pos位置处进行增添!请大家分清楚!!

    //给 pos 位置的元素设为 value
    public void set (int pos , int value) {
        checkIndex(pos); //首先要检查pos位置的合法性!!
        elem[pos] = value;
    }

这个代码也是挺简单的!!是不??各位老铁!!

9.删除第一次出现的关键字key

对于这个要求,我们只要找到第一次出现的key,然后再依次移动,就可以了!!想象的确实挺简单 的,但是……代码确实很复杂(对于当前的我来说!!)

 //删除第一次出现的关键字key  时间复杂度为O(N)
    public boolean remove(int toRemove) {
        int index = indefOf(toRemove);//查找toRemove元素所对应的位置!
        if (index==-1) {
            System.out.println("没有这个元素!");
            return false;
        }
        for (int i = index; i < usedSize-1; i++) {
            elem[i]=elem[i+1];
        }
        usedSize--;//实时记录存储的数据个数!
        elem[usedSize] = 0;  //此时需要手动制空!
        //已经进行usedSize--了,此时的usedSize指向原来的usedSize-1的位置处!!
        return true;
    }

其实对于这个思路,再笔者进行学习的时候,都感觉有点儿绕口!!但是,当你进行深入的理解,以后,将会发现一片新大陆!!

 10. 清空顺序表

对于清空顺序表,其实有很多方法!想到清空,肯定用数组来遍历一遍,每个元素都置为0(引用类型置为null)但是,这样显得不就变得复杂化了吗??其实最简单的办法,就是,将usedSize=0就可以了!!因为,每一个方法的使用,都是用usedSize作为基础来进行调动的!!所以有了下面的简简单单的一行代码:

   // 清空顺序表
    public void clear() {
        usedSize=0;
    }

该数组是以usedSize为基础进行的,当usedSize为0的时候,那么就没有办法……

到目前为止,上面的十个方法都已经写完了!关键不知道大家有没有看懂也!!有点小尴尬!!

那么下面笔者便把这个顺序表所用的代码全部在下文进行列举出来!请大家注意一下文件名!!

Test.java文件当中的内容为:

public class Test {
    public static void main(String[] args) {
        MyArraylist myArraylist = new MyArraylist();
        myArraylist.add(1);
        myArraylist.add(2);
        myArraylist.add(3);
        myArraylist.display();
        myArraylist.clear();

        try{
            myArraylist.add(1,99);
        }catch (IndexoutOfException e){
            e.printStackTrace();
        }
        myArraylist.display();
        try {
            System.out.println(myArraylist.get(4));
        }catch (IndexoutOfException e) {
            e.printStackTrace();
        }
    }
}

MyArrayList.java文件当中的内容为:

import java.util.Arrays;

public class MyArraylist {
    public int[] elem; //该数组在定义的时候,初始状态下默认为null
    public int usedSize;//记录存储了多少个数据
    public static final int DEFAULT_SIZE =5;//定义数组的长度

    public MyArraylist(){
        this.elem=new int[DEFAULT_SIZE];//定义数组的长度
    }

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            //usedSize是数组存储的有效数字
            System.out.print(this.elem[i]+" ");
        }
        System.out.println();
    }

    //获取顺序表长度
    public int size () {
        return usedSize;
    }

    // 判定是否包含某个元素
    public boolean contains (int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i]==toFind) {
                return true;
            }
        }
        return false;
    }

    //查找某个元素对应的位置
    public int indefOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
        //返回-1,是因为数组中没有负数下标
    }

    //新增元素,默认在数组最后新增
    public void add(int data) {
        if (this.isFull()) {  //判断数组是否已经存储满了??
            resize();//扩容
        }
        this.elem[this.usedSize]=data;
        this.usedSize++;
    }

    //扩容
    private void resize() {
        this.elem= Arrays.copyOf(this.elem,2*this.elem.length);
        //实现数组扩容,并且将扩容好的重新赋值给elem
    }

    //判断数组是否已经存储满了??
    public boolean isFull() {
        //方法1
        if (this.usedSize==this.elem.length) {
            return true;
        }
        return false;

        //方法2:
        //return this.usedSize==this.elem.length;
    }

    //在 pos 位置新增元素  时间复杂度为O(N)
    public void add(int pos , int data) {
        checkIndex(pos);//首先要检查pos的位置是否合法??
        if (isFull()) {  //判断数组是否存储满了??
            resize();//扩容
        }
        for (int i = usedSize-1; i >= pos; i--) {
            elem[i+1] = elem[i];
        }
        elem[pos] =data;
        usedSize++;
    }

    //检查add数据的时候,判断pos是否合法??
    private void checkIndex(int pos) {
        if (pos <0 || pos >=usedSize)
        throw new IndexoutOfException("get获取元素的时候,位置不合法!" +
                "请检查位置的合法性!!");
        //当pos的位置不合法的时候,抛出异常!!
    }

    //获取 pos 位置的元素
    public int get(int pos) {
        checkIndex(pos);//检查pos的合法性!
        return elem[pos];
    }

    //给 pos 位置的元素设为 value
    public void set (int pos , int value) {
        checkIndex(pos); //首先要检查pos位置的合法性!!
        elem[pos] = value;
    }

    //删除第一次出现的关键字key  时间复杂度为O(N)
    public boolean remove(int toRemove) {
        int index = indefOf(toRemove);//查找toRemove元素所对应的位置!
        if (index==-1) {
            System.out.println("没有这个元素!");
            return false;
        }
        for (int i = index; i < usedSize-1; i++) {
            elem[i]=elem[i+1];
        }
        usedSize--;//实时记录存储的数据个数!
        elem[usedSize] = 0;  //此时需要手动制空!
        //已经进行usedSize--了,此时的usedSize指向原来的usedSize-1的位置处!!
        return true;
    }

    // 清空顺序表
    public void clear() {
        usedSize=0;
    }
}

IndexoutOfException.java 文件当中的内容为:

public class IndexoutOfException extends RuntimeException{
    public IndexoutOfException() {

    }

    public IndexoutOfException(String msg) {
        super(msg);
    }
}

上述代码总的实现结果为:

注意:本文主要为了讲解一下顺序表之ArrayList的实现过程!!并不做其他的必须性!!对于最后的运行结果若有其他要求,请各位读者自行在Test中的main方法中进行更改!!

若有其他疑问,请及时联系笔者进行私聊哟!!

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

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

相关文章

Go项目实战:01-聊天室+map竞争需要上锁

实现一个聊天室&#xff08;群&#xff09;&#xff1a; 功能分析&#xff1a; 1、上线下线2、聊天&#xff1a;其他人和自己都可以看到聊天消息3、查询当前的聊天室用户所有人的名字4、可以修改自己的名字5、超时潜水踢出机制 技术点分析&#xff1a; 1、socket tcp编程2、…

Adam算法及python实现

文章目录算法介绍代码实现结果展示参考算法介绍 Adam算法的发展经历了&#xff1a;SGD->SGDM->SGDNA->AdaGrad->AdaDelta->Adam->Adamax的过程。它是神经网络优化中的常用算法&#xff0c;在收敛速度上比较快&#xff0c;比SGD对收敛速度的纠结上有了很大的…

单商户商城系统功能拆解46—应用中心—足迹气泡

单商户商城系统&#xff0c;也称为B2C自营电商模式单店商城系统。可以快速帮助个人、机构和企业搭建自己的私域交易线上商城。 单商户商城系统完美契合私域流量变现闭环交易使用。通常拥有丰富的营销玩法&#xff0c;例如拼团&#xff0c;秒杀&#xff0c;砍价&#xff0c;包邮…

基于微信小程序的课程分享平台-计算机毕业设计

项目介绍 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整…

[附源码]Node.js计算机毕业设计高校就业管理信息系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

学生竞赛网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 模块划分&#xff1a;通知类型、通知信息、学院信息、学生信息、学科信息、竞赛信息、报名信 息、成果上传、评分排名 管…

YOLOv5小目标切图检测

当我们在检测较大分辨率的图片时&#xff0c;对小目标的检测效果一直是较差的&#xff0c;所以就有了下面几种方法&#xff1a; 将图片压缩成大尺寸进行训练&#xff08; 想法&#xff1a;没显存&#xff0c;搞不来&#xff09;添加小检测头&#xff08;想法&#xff1a;P5模型…

【爬虫实战项目】Python爬虫批量下载相亲网站数据并保存本地(附源码)

前言 今天给大家介绍的是Python爬虫批量下载相亲网站图片数据&#xff0c;在这里给需要的小伙伴们代码&#xff0c;并且给出一点小心得。 首先是爬取之前应该尽可能伪装成浏览器而不被识别出来是爬虫&#xff0c;基本的是加请求头&#xff0c;但是这样的纯文本数据爬取的人会…

数据结构---树和二叉树

树和二叉树定义二叉树二叉树的物理结构链式存储数组二叉树应用查找维持相对顺序二叉树的遍历深度优先遍历前序遍历中序遍历后序遍历二叉树广度优先遍历层序遍历定义 有且仅有一个特定的称为根的节点。当n>1时&#xff0c;其余节点可分为m&#xff08;m>0&#xff09;个互…

数据结构与算法——Java实现栈、逆波兰计算器(整数加减乘除)

目录 一、栈 1.1 基本介绍 1.2 栈的思路分析 1.3 栈的代码实现 二、栈实现综合计算器 2.1 思路分析 2.2 代码实现&#xff08;中缀表达式实现&#xff09; 三、栈的前缀&#xff08;波兰&#xff09;、中缀、后缀&#xff08;逆波兰&#xff09;表达式 3.1 表达式的介绍…

访问pcie总线地址内容

调用代码如下&#xff1a; uint32_t value;void * addr;printk("------1--------\n");addr0x2730000;struct resource *res;char const *name dev_name(&pdev->dev);printk("dev_name%s\n", name);res request_mem_region(addr, 16, "name1&…

【语音之家公开课】SRD: A Dataset and Benchmark Perspective

本次语音之家公开课邀请到陈果果进行分享Speech Recognition Development: A Dataset and Benchmark Perspective。 公开课简介 主题&#xff1a;Speech Recognition Development: A Dataset and Benchmark Perspective 时间&#xff1a;12月15日&#xff08;周四&#xff09…

web网页设计期末课程大作业:美食餐饮文化主题网站设计——HTML+CSS+JavaScript美食餐厅网站设计与实现 11页面

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

C# IO及文件管理

一 System.IO ① System.IO名字空间&#xff1b; ② 提供了许多用于&#xff1b; ③ 文件和数据流进行读写操作的类&#xff1b; 二 流的分类 1 Stream类 按存取位置分&#xff1a;FileStream,MemeryStream,BufferedStream; 2 读写类 BinaryReader和BinaryWriter; TextRe…

从 0 到 1 搞一个 Compose Desktop 版本的玩天气之打包

从 0 到 1 搞一个 Compose Desktop 版本的玩天气之打包 大家好&#xff0c;前两篇文章大概介绍了下上手 Compose Desktop 和自定义绘制时遇到的一些问题&#xff0c;项目的最终实现效果如下&#xff1a; 视频代码写好了&#xff0c;该弄的动画也弄了&#xff0c;该请求的网络数…

【数据结构】八大排序算法详解

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《数据结构》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 排序前言一…

汇编语言第一章:基础知识

1. 基础知识 机器语言 机器语言是机器指令的集合&#xff0c;是一台机器可以正确执行的命令。现在一般电子计算机的机器指令是一列二进制数字。机器指令集是机器语言。 汇编语言 机器语言难以辨别和记忆&#xff0c;所以产生了汇编语言。汇编语言的主体是汇编指令。 操作&…

on-device training

又搬来个好玩呃 说来又想试试了 , 仅用256KB就实现单片机上的神经网络训练&#xff08;training,notinference&#xff09;&#xff0c;从此终端智能不再是单纯的推理&#xff0c;而是能持续的自我学习自我进化 On-Device Training under 256KB Memory 说到神经网络训练&#…

编译原理实验四

编译原理实验四 实验要求 cminus-f的词法分析和语法分析部分已经完成&#xff0c;最终得到的是语法分析树。而为了产生目标代码&#xff0c;还需要将语法分析树转为抽象语法树&#xff0c;通过抽象语法分析树生成中间代码(即IR)&#xff0c;最后使用中间代码来进行优化并生成…

easyExcel导出表头合并 不得不说真牛

有个导出单元格合并的任务&#xff0c;表头不规则合并格式&#xff0c;看得就烦&#xff0c;尤其是对于没玩儿过合并的我来说&#xff0c;任务放在哪里不知咋做&#xff0c;网上也看了一堆合并的方法&#xff0c;自己写注解来写的那些&#xff0c;麻烦得要命&#xff0c;我写一…