【数据结构】认识顺序表

news2024/12/25 1:43:01

目录

1、先来认识一下线性表

1.1、对非空的线性表或者线性结构的特点:

 1.2、线性表的实现方式

2、顺序表 

2.1、定义一个类,实现顺序表

2.2、顺序表的操作方法

2.2.1、打印顺序表(display)

2.2.2、获取顺序表的长度(size)

2.2.3、判断顺序表中是否包含某个元素(contains)

2.2.4、查找某个元素对应的位置(indexOf)

2.2.5、新增元素,默认在数组最后新增(add)

 2.2.6、在pos位置新增元素

 2.2.7、获取pos位置的元素

 2.2.8、将pos位置的元素修改为value

 2.2.9、删除某个位置的元素

 2.2.10、清空顺序表


1、先来认识一下线性表

  • 线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列...
  • 线性表在逻辑上线性结构,也就是说连续的一条直线。但是在物理结构上不一定是连续的,线性表在物理上存储时,通常以顺序结构链式结构的形式存储。

1.1、对非空的线性表或者线性结构的特点:

  1. 线性表中第一个元素被称为表头元素,有且只有一个。
  2. 线性表中最后一个元素被称为表尾元素,有且之后一个。
  3. 除表头元素外,结构中的每个数据元素有且只有一个直接前驱;
  4. 出表尾元素外,结构中的每个数据元素有且只有一个直接后继;

 1.2、线性表的实现方式

线性表有两种实现方式:

  • 顺序存储结构:简称顺序表
  • 链式存储结构:简称链表


2、顺序表 

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

2.1、定义一个类,实现顺序表

public class MyArrayList {
    public int[] elem;
    public int useSize;//当前数组当中存储了多少数据。
    public static final int DEFAULT_SIZE = 10;
    public MyArrayList(){//定义一个数组默认大小为10
        this.elem = new int[DEFAULT_SIZE];
    }
    //重载MyArrayList方法,初始化数组的时候,数组大小由调用者,控制
    public MyArrayList(int d){
        this.elem = new int[d];
    }
}

2.2、顺序表的操作方法

2.2.1、打印顺序表(display)

通过遍历来打印顺序表,在定义类的时候useSize被用来记录数组当中录入的元素的个数,所以录入多少个元素,遍历多少(useSize)次。只打印有效元素。

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

2.2.2、获取顺序表的长度(size)

直接将useSize的值返回就可以。

 public int size(){
        return this.useSize;
    }

2.2.3、判断顺序表中是否包含某个元素(contains)

通过循环来查找顺序表中是否存在这个元素,若有,输出true,若没有,输出false

public boolean contains(int toFind){
        for(int i = 0;i < this.useSize;i++){
            if(this.elem[i] == toFind){//因为在定义数组的时候,采用的是基本数据类型,所以这里使用==比较
//若定义数组的时候采用的是引用数据类型,则使用equals方法来进行比较
                return true;
            }
        }
        return false;
    }

2.2.4、查找某个元素对应的位置(indexOf)

    public int indexOf(int toFind) {
        for (int i = 0; i < this.useSize; i++) {
            if (this.elem[i] == toFind) {
                return i;//找到这个数据返回下标。
            }
        }
        return -1;//这里返回-1 ,因为数组没有 负数下标。
    }

2.2.5、新增元素,默认在数组最后新增(add)

主要逻辑就是在useSize位置,将新元素放入。但是这里存在一个问题,就是数组在满了的情况下,再存入数据,就会数组越界,那么还得判断数组是否满了,满了对数组进行扩容。

    /*
    * 判断数组是否满了
    */
    public Boolean isFull(){
        if(this.useSize == this.elem.length){
            return true;
        }
        return false;
//也可以直接return
        //return this.useSize == this.elem.length
    }
/*
*扩容,对原来的数组扩大原来的2倍
*/
private void resize(){
        this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
    }
   public void add(int data){
        if(this.isFull()){
            resize();//扩容,对原来的数组扩大二倍
        }
        this.elem[this.useSize] = data;
        this.useSize++;
    }

对add这个方法进行测试

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.display();
        myArrayList.add(5);
        myArrayList.display();
        myArrayList.add(6);
        myArrayList.display();
}

当添加6元素的时候,数组发生扩容。

 2.2.6、在pos位置新增元素

在有效元素的某个位置,插入一个数据,就需要将某个位置在内的,后面所有的数据整体向后移动。

例如,在下标为2的位置插入一个数据,就需要将2下标以后的数据整体向后移动

编写思路:

  • 找到有效数组的最后一位的下标为useSize-1,从后往前 (目标位置),将元素像后移动一个,数组下标 向前移动一位,当数组下标小于目标位置下标时,结束。
  • 当然主逻辑写完之后,还有判断pos的合法性
  1. pos不能是负数,数组没有负数下标;
  2. 在顺序表中,除了表头元素外,每个元素都要自己的直接前驱,所以上述的图片中,不能直接在5位置插入数据。
  3. 在顺序表中,除了表尾元素外,每个元素都要有自己的直接后继.

 代码示例:

   //在pos位置新增数据
    public void add(int pos,int data){
        checkAddindex(pos);//检查pos的合法性
        if(isFull()){//检查数组是否满了
           resize();//满了进行扩容
        }
        for (int i = useSize-1; i >= pos; i--) {
            elem[i+1] = elem[i];
        }
        elem[pos] = data;
        useSize++;
    }
    /*
    * add方法的,检查add数据的时候,pos是否是合法的
    * */
    private void checkAddindex(int pos){
        if(pos < 0 || pos > useSize){//数组的useSize位置没有元素,所以useSize位置之后不能插入元素
            throw new AddIndexOutOfException("add元素的时候,位置不合法,请检查位置的合法性");
        }
    }

测试一下这个方法

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.display();
        try{
            myArrayList.add(1,99);
        }catch(AddIndexOutOfException e){
            e.printStackTrace();
        }
        myArrayList.display();
    }

 2.2.7、获取pos位置的元素

  • 直接返回pos位置的元素就可以,
  • 当然也要检查pos位置的合法性,这里的检查pos位置合法性(checkGetIndex),当要获取pos位置的元素时,useSize下标处,没有元素,所以不用获取该下标的元素。
//    获取pos位置的元素
    public int get(int pos){
        checkGetIndex(pos);
        return elem[pos];
    }
/*
*get方法的,检查pos位置的合法性
*/
    private void checkGetIndex(int pos){
        if(pos < 0 || pos >= useSize){//想要得到pos下标位置的元素的时候,useSize位置没有元素,所以不用得到该下标的元素。
            throw new IndexOutOfException("get获取元素的时候,位置不合法,请检查位置的合法性");
        }
    }
}

对该方法进行检测

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.display();
        try{
            System.out.println(myArrayList.get(2));
        }catch(IndexOutOfException e){
            e.printStackTrace();
        }
    }

当想要获取4下标的元素,4下标没有元素,所以编译器会报错异常

  try{
            System.out.println(myArrayList.get(4));
        }catch(IndexOutOfException e){
            e.printStackTrace();
        }
    }

 2.2.8、将pos位置的元素修改为value

  • 将数组pos位置的元素修改为value
  • 当然这里也要检查pos位置的合法性,这里只需要调用checkIndex方法即可。
  • 要修改元素,首先要在数组的有效范围内修改,那么当数组当中元素放满的时候,不能超过数组的最大范围,所以pos要小于useSize,也要大于0下标。
  //检查pos位置的合法性
  private void checkIndex(int pos){
        if(pos < 0 || pos >= useSize){//当数组放满时,useSize下标是越界的。
            throw new IndexOutOfException("位置不合法,请检查位置的合法性");
        }
    }
    //将pos位置的元素修改为value
    public void set(int pos, int value) {
        checkIndex(pos);
        elem[pos] = value;
    }
}

测试该方法

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.add(5);
        myArrayList.set(5, 12);

        myArrayList.display();
}

 2.2.9、删除某个位置的元素

 思路:

  1. 首先调用IndexOf方法,查找某个元素对应的位置,有查找的元素,返回该数据的下标,若没有,返回-1;
  2. 再判断IndexOf方法返回的是-1,则提示没有这个数据,返回false,该方法结束。
  3. 再循环将数组元素向前挪动;
  4. 删除一个元素之后,数组的有效元素个数减一;
  5. 现在数组实际存在5个元素,但是删除以为之后,应该只剩4位,所以对最后一位置0.

代码:

   //删除数组中的某个元素
    public boolean remove(int toRemove){
        int index = indexOf(toRemove);//查找数组中,某个元素对应的位置。
        if(index == -1){
            System.out.println("没有这个数据");
            return false;
        }
        for (int i = index; i < useSize-1; i++) {
            elem[i] = elem[i+1];
        }
        useSize--;
        elem[useSize]=0;//这里因为useSize--,所以直接将elem[useSize]元素置0。
       // elem[useSize]=null;当数组类型是引用类型时,将其值为null.
        return true;
    }
}

对该方法进行测试

public class Test {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);
        myArrayList.add(4);
        myArrayList.add(5);
        myArrayList.remove(2);//删除数组的元素2
        myArrayList.display();
    }
}

 

 ❗❗❗提示:这个方法的时间复杂度位O(N);

 2.2.10、清空顺序表

   public void clear(){
        /*当数组的类型为引用数据类型时,可以用这种写法
        * for(int i = 0 ;i < useSize; i++){
        *       elem[i] = null;
        * }
        * */
        useSize = 0;
    }

通过调试来看

 

将useSize置为0,可以看见数组当中的元素没有置0.

通过运行代码可以看见 ,通过调用打印方法,没有输出结果。因为再写输出方法(display)时,是通过for循环来输出的,for循环通过useSize类控制。

 ❗❗❗总结:

  • 顺序表(ArrayList)底层采用连续的空间,任意位置的元素插入和删除,都需要将元素整体向后或者先前挪动,再最坏的情况下,他们的时间复杂度都为O(N).
  • 顺序表不是很适合,频繁的对数据进行插入和删除的场景。
  • 顺序表适合,给定下标的随机访问,它的效率非常的高。
  • 增容需要申请空间,拷贝数组,释放空间。会有不小的消耗。
  • 增容一般时成2倍的增长,势必会有一定的空间浪费。例如当前空间为5,满了以后增容到10,我们再继续插入了1个数据,后面没有数据插入了,那么就造成了4个空间的浪费。

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

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

相关文章

Rancher 中使用 Longhorn 备份恢复数据卷

全文目录导航0. 前言1. NFS 安装配置1.1 安装 nfs 及 rpcbind1.2 创建共享目录1.3 配置访问权限1.4 限制 showmount -e 防止漏洞扫描1.5 防火墙配置2. Longhorn 备份配置2.1 在 Longhorn UI 中配置3. 数据卷备份恢复操作3.1 创建示例工作负载3.2 创建测试数据3.3 创建数据卷备份…

车载以太网 - SomeIP测试专栏 - SomeIP Header - 03

前面已经简单的介绍了整帧SomeIP报文的组成部分,由于Ethernet报文头都是通用的,因此不会做详细的介绍,当然后面在介绍TC8中的TCP、UDP、IPv4、IPv6的时候也会做简单的介绍。不过在这里就不做介绍了,我们直接介绍SomeIP。 SomeIP Header 一、Message ID Message ID是由Serv…

Web3中文|构建Web3融资交易:股权和内部代币分配的比例

2017年&#xff0c;首次币发行&#xff08;ICO&#xff0c;Initial Coin Offering&#xff0c;也称首次代币发售、区块链众筹&#xff0c;是用区块链把使用权和加密货币合二为一&#xff0c;来为开发、维护、交换相关产品或者服务的项目进行融资的方式&#xff09;的融资方式激…

聚观早报 | 抖音超市上线;首架国产大飞机 C919 完成首次飞行

今日要闻&#xff1a;抖音超市上线&#xff1b;首架国产大飞机 C919 完成首次飞行&#xff1b;小鹏汽车计划有 5 款车型上市&#xff1b;2023年春节档电影总票房67.58亿元&#xff1b;亚洲首富被空头重创抖音超市上线 1 月 28 日消息&#xff0c;抖音超市已上线抖音 App&#x…

Javadoc(文档注释)详解

Java 支持 3 种注释&#xff0c;分别是单行注释、多行注释和文档注释。文档注释以/**开头&#xff0c;并以*/结束&#xff0c;可以通过 Javadoc 生成 API 帮助文档&#xff0c;Java 帮助文档主要用来说明类、成员变量和方法的功能。文档注释只放在类、接口、成员变量、方法之前…

vue+element高度仿照QQ音乐,完美实现PC端QQ音乐

一.前言 QQ音乐官网&#xff1a;点击访问作者成品效果预览&#xff1a;点击访问作者其他博客成品汇总预览&#xff1a;点击访问 暂时源码并没有提供其他获取渠道&#xff0c;私聊作者获取即可&#xff0c;或通过博客后面名片添加作者&#xff0c;很简单&#xff01; 二.主要…

创建的vue项目--打包

自创建的项目&#xff08;未使用项目框架&#xff09;&#xff0c;使用weabpack打包 1.在package.json文件中配置 2.在控制台执行打包命令npm run build 打包完成后&#xff0c;会在项目中生成一个dist文件夹&#xff0c;其中就是打包生成的静态文件 3.打开index.html&…

RocketMq基础详解

1、RocketMq的架构&#xff1a; 在RocketMq中有四个部分组成&#xff0c;分别是Producer&#xff0c;Consumer&#xff0c;Broker&#xff0c;以及NameServer&#xff0c;类比于生活中的邮局&#xff0c;分别是发信者&#xff0c;收信者&#xff0c;负责暂存&#xff0c;传输的…

找到二叉树中的最大搜索二叉树

题目 给定一棵二叉树的头节点 head&#xff0c;一致其中所有节点的值都不一样&#xff0c;找到含有节点最多的搜索二叉树&#xff0c;并返回这棵子树的头节点。 示例 分析 树形dp套路&#xff1a;如果题目求解目标是S规则&#xff0c;则求解流程可以定成以每一个节点为头节点…

【前端】如何判断是页面滚动还是窗口滚动

在写项目的时候遇到这个问题&#xff0c;现在举两个例子来记录这个问题。 页面滚动 html: <div class"temp"><template v-for"item in 100"><div>{{ item }}</div></template> </div>css: .temp {height: 100px;o…

老马闲评数字化「3」业务说了算还是技术说了算?

原文作者&#xff1a;行云创新CEO 马洪喜 导语 前两集和大伙聊了一下“数字化不转型行不行”以及“你的企业急不急着转”这两个话题。后面收到不少朋友的消息&#xff0c;说写的挺好&#xff0c;但“急着转、不敢转”的情况非常的普遍&#xff0c;有没有啥好主意给说一说。 麦…

冬去春来,ToB行业压缩的弹簧就要迸发了

目前来看&#xff0c;认知、实践、技术、服务这四方面的新变化&#xff0c;都将成为2023年企业数智化业务需求“井喷”的重要原因。 作者|周羽 出品|产业家 2023&#xff0c;冬去春来。 不止于字面。新的一年&#xff0c;中国的ToB厂商即将迎来“拨云见日”的朗朗晴空。 …

[文件上传工具类] MultipartFile 统一校验

目录​​​​​​​ 1. 创建上传文件的统一校验类 包含功能: -> 1. 多文件上传校验 -> 2. 文件名字校验(特殊符号) -> 3. 文件后缀校验 2. 使用方式 建议: 在文件上传开始的位置添加 -> 两个重载方法, 单文件 多文件都支持 -> 示例: 直接可以用, 任意位…

C++ 包装器function

目录 1、为什么需要包装器&#xff1f; 2、包装器的声明和使用 (1) 声明 (2) 实际应用 (3) 包装器接收类成员函数 3、包装器的绑定&#xff1a;bind函数 (1) 调整参数顺序 (2) 调整参数个数 1、为什么需要包装器&#xff1f; 函数模板可以接收各种不同类型的参数&…

光流正负值的含义以及如何利用光流进行warping

本文主要介绍光流的形式&#xff0c;光流值的正负代表什么含义&#xff0c;以及如何利用光流进行warping。 1. 光流正负值的含义 光流的概念&#xff1a;光流表示的是从reference frame到target frame&#xff0c;物体的移动。光流的形式&#xff1a;光流的表示也是数字化的。…

镭速-跨国车企数据高速、安全跨境传输解决方案

一、背景及趋势 在新一代信息技术驱动的数字经济时代&#xff0c;数据已然成为新型生产要素&#xff0c;是国家基础性资源和战略性资源。在汽车市场全球化背景下&#xff0c;产品、数据双跨境将成为车企未来常态。数据的价值核心在于流通和应用&#xff0c;但数据也牵涉着竞争…

23.1.30 将TF-A源码移植的过程,整理成自己的笔记

将TF-A源码移植的过程&#xff0c;整理成自己的笔记&#xff0c;上传到CSDN 一、配置TF-A源码 自动探测 自动换行 1.对tf-a源码进行解压 tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz 打补丁 3.进入tf-a源码目录 $> cd tf-a-stm32mp-2.2.r2 4.打补丁命令 $> for p in ls -1 .…

JavaScript中的Array对象~

初识Array&#xff1a; Array 对象用于在单个的变量中存储多个值 定义&#xff1a; 方式1 //返回的数组为空&#xff0c;length字段为0 var 变量名new Array(); //size是期望的数组元素个数&#xff0c;返回的length字段将被设置为size的值--返回具有指定个数&#xff0c;元…

vue2面试题持续更新。。。

文章目录1、vue 修改数据页面不重新渲染数组/对象的响应式 &#xff0c;vue 里面是怎么处理的&#xff1f;2、生命周期Vue 生命周期都有哪些&#xff1f;父子组件生命周期执行顺序3、watch 和 computed 的区别4、组件通信&#xff08;组件间传值&#xff09;5、$nextTick6、修饰…

postman常用变量总结

一、变量分类环境变量&#xff1a;只在所属环境内使用&#xff1b;全局变量&#xff1a;整个postman中全部接口皆可使用该变量&#xff1b;集合变量&#xff1a;只在设置的集合中可使用&#xff0c;且与环境无关&#xff1b;局部变量数据变量二、环境变量设置方式方式一方式二方…