Java顺序表解析与应用

news2024/12/23 8:14:13

一、顺序表概念

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

二、主要功能接口实现

Java顺序表底层就是一个动态数组。其主要功能接口如下:

// 1.打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() { }
// 2.新增元素,默认在数组最后新增
public void add(int data) { }
// 3.判断当前的顺序表是不是满的
public boolean isFull() { }
// 4.在 pos 位置新增元素
public void add(int pos, int data) { }
// 5.判定是否包含某个元素
public boolean contains(int toFind) { return true; }
// 6.查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
// 7.获取 pos 位置的元素
public int get(int pos) { return -1; }
// 8.给 pos 位置的元素设为 value
public void set(int pos, int value) { }
// 9.删除第一次出现的关键字 key
public void remove(int toRemove) { }
// 10.获取顺序表长度
public int size() { return 0; }
// 11.清空顺序表
public void clear() { }

下面我们对应上面的功能接口,自己实现一下顺序表(由于这部分比较简单这里就直接给出代码,大家可结合注释参考。另外此处侧重于流程实现,使用了更好理解的int类型,并未使用泛型):

import java.util.Arrays;
public class MyArraylist {

    public int[] elem;
    // 已使用容量,初始为0
    public int usedSize;
    // 默认容量
    private static final int DEFAULT_SIZE = 5;
	// 这里采用无参的构造方法
    public MyArraylist() {
        this.elem = new int[DEFAULT_SIZE];
    }
	
    /**
     * 1.打印顺序表  
     * 注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
     * 根据usedSize判断即可
     */
    public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
    }

	/**
	* 2.新增元素,默认尾插
	*/ 
    public void add(int data) {
        if (isFull()) {
            resize();
        }
        this.elem[this.usedSize] = data;
        this.usedSize++;
    }
	
    // 扩容
    private void resize() {
        this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
    }

	// 检查坐标合法性
    private void checkPosInAdd(int pos) {
        if (pos < 0 || pos > this.usedSize) {
        	// 这里自定义异常类
            throw new IndexException("位置不合法,请检查位置的合法性!");
        }
    }

    /**
    * 3.判断当前的顺序表是不是满的
    */
    public boolean isFull() {
        return this.usedSize == this.elem.length;
    }
	
	/**
    * 4.在 pos 位置新增元素!
    */
    public void add(int pos, int data) {
        if (isFull()) {
            resize();
        }
        checkPosInAdd(pos);
        for (int i = this.usedSize; i > pos; i--) {
            this.elem[i] = this.elem[i - 1];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }

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

	/**
    * 6.查找某个元素对应的位置
    */
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

	/**
    * 7.获取 pos 位置的元素
    */
    public int get(int pos) {
        checkPosInAdd(pos);

        return this.elem[pos];
    }

	// 判空
    private boolean isEmpty() {
        if (this.usedSize == 0) {
            return true;
        }
        return false;
    }

	/**
    * 8.将 pos 位置的元素设为修改为: value
    */
    public void set(int pos, int value) {
        checkPosInAdd(pos);
        this.elem[pos] = value;
    }

    /**
    * 9.删除第一次出现的关键字key
    */
    public boolean remove(int key) {
        int index = indexOf(key);
        if (index == -1) {
            System.out.println("不存在关键字" + key);
            return false;
        }
        for (int j = index; j < this.usedSize - 1; j++) {
            this.elem[j] = this.elem[j + 1];
        }

        this.usedSize--;
        //注意:是在这条语句之后
        //elem[usedSize] = null;
        // 如果里面是引用类型 那么此时就需要手动置空
        elem[usedSize] = 0;
        return true;

    }

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

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

上述过程中自定义的异常类:

public class IndexException extends RuntimeException {
	// 帮助父类构造
    IndexException() {
        super();
    }
    IndexException(String msg) {
        super(msg);
    }
}

三、Java集合框架中的 ArrayList

java.util 包下为我们提供了一个ArrayList类,ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表,且这里的 ArrayList 是以泛型方式实现的,使用时必须要先实例化。此外在Java中还对ArrayList有以下这些说明:(现阶段不做解释,大家可以暂时了解即可)

  1. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  2. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  3. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  4. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者 CopyOnWriteArrayList

1、ArrayList的构造方法

方法解释
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量

解释:

  1. 对于无参构造方法ArrayList(),在实例化ArrayList对象时不会分配内存,在add()方法中才进行内存分配。
  2. 对于ArrayList(Collection<? extends E> c),表示可以将实现了Collection接口、并且是E类型或E类型的子类的集合作为参数构造ArrayList。
  3. 相比之下ArrayList(int initialCapacity)就比较好理解了,这个构造方法是在实例化ArrayList对象时,分配指定initialCapacity大小的容量。

2、ArrayList常用方法

与此同时,ArrayList下为我们提供了大量的方法,其中常见操作方法如下:

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean isEmpty()如果此列表不包含元素,则返回 true
int size()返回此列表中的元素数
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

3、ArrayList 的继承关系

在《Java集合框架中》我们介绍了Java集合中的继承关系,你是否还有印象ArrayList实现了List接口:

对于List接口来说,里面涵盖了ArrayList中的方法,也就是说我们可以使用 List 接口对 ArrayList 实例进行操作,因此我们可以写出类似这种调用方式:List<Integer> list = new Arraylist<>(); 将ArrayList实例交给List接口,然后直接使用list进行相关操作。

public class OperateTest {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        list.add(333);
        list.add(444);
        list.add(555);
        System.out.println(list);
        // 设定list2->[1,2,3] 便于测试addAll()
        List<Integer> list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        // 末尾插入list2
        list.addAll(list2);
        System.out.println(list);

        // 获取list中有效元素个数
        System.out.println(list.size());

        // 获取和设置index位置上的元素,注意index必须介于[0, size)间
        System.out.println(list.get(0));
        list.set(0, 999);
        System.out.println(list.get(0));

        // 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置
        list.add(1, 888);
        System.out.println(list);

        // 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置
        // (这里如果直接写444会默认下标,需要使用引用类型)
        list.remove(new Integer(444));
        System.out.println(list);

        // 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常
        list.remove(list.size()-1);
        System.out.println(list);

        // 检测list中是否包含指定元素,包含返回true,否则返回false
        if(!list.contains(123456)){
            list.add(123456);
            System.out.println(list);
        }
        // 查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找
        System.out.println(list.indexOf(333));
        System.out.println(list.lastIndexOf(333));

        // 使用list中[0, 4)之间的元素构成一个新的SubList返回,
        // 但是和ArrayList共用一个elementData数组(对任一部分修改会影响整个部分)
        List<Integer> ret = list.subList(0, 2);
        System.out.println(ret);

        // 清空
        list.clear();
        System.out.println(list.size());
    }
}

4、ArrayList的遍历

(1) 方式一:
使用for循环+下标遍历

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

(2) 方式二:
由于List、Arraylist集合实现了iterable接口,可以使用增强的for循环-foreach

for (Integer x:list) {
    System.out.println(x);
}

(3) 方式三:
对于Java而言只要实现了Iterable接口的集合就可以使用迭代器 iterator

Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
    System.out.println(it.next());
}

总结

本篇文章主要介绍了 Java 集合中的线性结构 ArrayList ,这是一个相对比较简单,且容易理解和实现的数据结构。这里就简单总结一下顺序表 ArrayList的优缺点:

顺序表缺点:

  1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈倍数增长。假如以2倍扩容,势必会有一定的空间浪费,例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

顺序表优点:

  1. 当给定下标的时候,查找速度非常快,复杂度为O(1)

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

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

相关文章

stack(栈)和queue(队列)

目录 1.stack的介绍和使用(栈) 1.1 stack的介绍 1.2 stack的使用 1.3stack的模拟实现 2.queue的介绍和使用(队列) 2.1queue的介绍 2.3queue的模拟实现 3.priority_queue的介绍和使用 3.1priority_queue的介绍 3.2 priority_queue的使用 3.3priority_queue的模拟实现 …

高忆管理:碳酸锂期现货价格大幅回落 行业期盼找回“价格之锚”

6月末以来&#xff0c;国内碳酸锂价格的反弹态势戛然而止&#xff0c;再度陷入接连跌落格式。现货方面&#xff0c;据上海钢联数据显现&#xff0c;电池级碳酸锂价格6月26日至今已接连22次下调&#xff0c;从31.50万元/吨下调至最新的25.60万元/吨&#xff1b;期货方面&#xf…

【问题解决】Git命令行常见error及其解决方法

以下是我一段时间没有使用xshell&#xff0c;然后用git命令行遇到的一些系列错误和他们的解决方法 遇到了这个报错&#xff1a; fatal: Not a git repository (or any of the parent directories): .git 我查阅一些博客和资料&#xff0c;可以解决的方式&#xff1a; git in…

MyBatis操作数据库常见用法总结2

文章目录 1.动态SQL使用什么是动态sql为什么用动态sql标签拼接标签拼接标签拼接标签拼接标签拼接 补充1&#xff1a;resultType和resultMap补充2&#xff1a;后端开发中单元测试工具使用&#xff08;Junit框架&#xff09; 1.动态SQL使用 以insert标签为例 什么是动态sql 是…

vue3+vite使用vite-plugin-svg-icons

使用vite-plugin-svg-icons插件显示本地svg图标 在开发项目的时候&#xff0c;经常会用到svg矢量图标&#xff0c;而且我们使用svg以后&#xff0c;页面上加载的不再是图片资源&#xff0c;这对页面性能来说是个很大的提升&#xff0c;而且我们svg文件比img要小很多&#xff0c…

使用xrdp协议远程桌面控制树莓派,无需公网IP!

远程桌面控制树莓派&#xff0c;我们可以用xrdp协议来实现&#xff0c;它内部使用的是windows远程桌面的协议。我们只需要在树莓派上安装xrdp&#xff0c;就可以在同个局域网下远程桌面控制树莓派。 而如果需要在公网下远程桌面控制树莓派&#xff0c;可以通过cpolar内网穿透&…

Linux固件子系统的实现机制简介

一、Linux固件子系统概述 固件是硬件设备自身执行的一段程序。固件一般存放在设备flash内。而出于成本和便利性的考虑&#xff0c;通常是先将硬件设备的运行程序打包为一个特定格式的固件文件&#xff0c;存储到终端系统内&#xff0c;通过终端系统给硬件设备进行升级。Linux内…

self-attention(自注意力机制)

先举个有趣的例子理解 Q 、 K 、 V Q、K、V Q、K、V&#xff1a; 将我们要查询的内容&#xff0c;和商品列表进行相似度匹配&#xff0c;先拿出相似度更高的商品列表。 再根据以往的评价&#xff0c;计算出总分&#xff0c;按照分数进行排序。 self-attention d k \sqrt{d_k}…

ubuntu 安装 python

ubuntu 安装 python 初环境与设备查询是否安装安装python 本篇文章将介绍ubuntu 安装 python 初 希望能写一些简单的教程和案例分享给需要的人 环境与设备 系统&#xff1a;ubuntu 查询是否安装 因为系统也许会自带一个python&#xff0c;所以验证一下&#xff0c;如果自…

Linux mysql5.7开启 binlog

查看 mysql是否开启 binlog。 查看命令&#xff1a; show variables like %log_bin%; log_bin OFF 是关闭的状态。 编辑my.cnf配置文件 vim /etc/my.cnf 默认的配置文件内容&#xff1a; 增加下面内容 server_id 1 binlog_format ROW log-bin mysql_log_bin 重启mysq…

uniapp 微信小程序 订阅消息

第一步&#xff0c;需要先去小程序官方挑选一下订阅模板拿到模板id 订阅按钮在头部导航上&#xff0c;所以 <u-navbar :bgColor"bgColor"><view class"u-nav-slot" slot"left" click"goSubscribe"><image :src"g…

【Java】try|catch|throws 具体详解+应用

目录 tryCatch 基本介绍 使用细节 throws异常处理 基本介绍 ​ 使用细节 自定义异常 基本概念 步骤 throw和throws的区别 tryCatch 基本介绍 使用细节 throws异常处理 基本介绍 使用细节 自定义异常 基本概念 步骤 throw和throws的区别

常见的软件项目质量管理5种方法

产品质量的重要性不言而喻&#xff0c;为了确保项目质量&#xff0c;我们需要快速高效地找出影响产品质量的因素。如果不能及时高效洞察影响因素&#xff0c;无法及时修复项目缺陷和Bug&#xff0c;往往会对项目造成意想不到的后果和风险&#xff0c;如需求变更、重要开发节点延…

【雕爷学编程】Arduino动手做(201)---行空板开发环境之Jupyter

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

数据库运维是什么意思?主要工作包含哪些?

还有不少小伙伴不知道数据库运维是什么意思&#xff1f;主要工作内容包含哪些&#xff1f;今天我们就一起来简单了解一下吧&#xff0c;仅供参考哦&#xff01; 数据库运维是什么意思&#xff1f; 数据库运维是指对数据库系统进行管理、监控和维护的过程&#xff0c;以确保数据…

CMU 15-445 -- Introduction to Distributed Databases - 19

CMU 15-445 -- Introduction to Distributed Databases - 19 引言System ArchitectureShared MemoryShared DiskShared Nothing Early Distributed Database SystemsDesign IssuesHomogeneous VS. Heterogeneous Database PartitioningNaive Table PartitioningHorizontal Part…

第一章 SpringBoot入门

1.SpringBoot简介 1.1.简介 Spring Boot来简化spring应用开发&#xff0c;约定大于配置去繁从简&#xff0c;just run就能创建一个独立的&#xff0c;产品级别的应用。 背景&#xff1a;J2EE笨重开发&#xff0c;繁多的配置、低下开发效率、复杂的部署流程、第三方技…

出现raise NotImplementedError报错

在学习《动手学深度学习》时&#xff0c;实现下面代码时&#xff0c;报出raise NotImplementedError错误。 import collections import torch from d2l import torch as d2l import math from torch import nnclass Seq2SeqEncoder(d2l.Encoder):def __init__(self,vocab_size,…

并发编程面试题2

并发编程面试题2 一、AQS高频问题&#xff1a; 1.1 AQS是什么&#xff1f; AQS就是一个抽象队列同步器&#xff0c;abstract queued sychronizer&#xff0c;本质就是一个抽象类。 AQS中有一个核心属性state&#xff0c;其次还有一个双向链表以及一个单项链表。 首先state…

NR sidelink(二) S-SSB

这篇看下NR sidelink S-SSB的内容,主要内容包括NR sidelink的同步原则,S-SSB的结构及相关序列,S-SSB的时频域位置,MasterInformationBlockSidelink IE解析,sidelink的同步过程,PSBCH payload及UE相关的能力IE。 NR sidelink的同步原则 参与sidelink通信之前,UE需要与覆…