Java数据结构-顺序表

目录

  • 1. 顺序表的相关概念
  • 1.1 线性表
  • 1.2 顺序表
  • 2. 功能实现
    • 2.1 整体框架
    • 2.2 乱七八糟的功能(bushi)
      • 2.2.1 判断容量是否满
      • 2.2.2 返回顺序表当前长度
      • 2.2.3 扩容
      • 2.2.4 清空整个顺序表
    • 2.3 插入数据
      • 2.3.1 头插数据
      • 2.3.2 尾插数据
      • 2.3.3 指定位置插入
    • 2.4 删除数据
      • 2.4.1 删除第一次出现的key
      • 2.4.2 删除所有的的key
    • 2.5 查找数据
      • 2.5.1 判定是否包含某个元素
      • 2.5.2 查找某个元素对应的位置
      • 2.5.3 pos位置不合法异常
      • 2.5.4 获取pos位置的元素:
    • 2.6 修改数据
  • 3. 全部代码

1. 顺序表的相关概念

1.1 线性表

线性表是一种常见的数据结构,它的特点是逻辑上是连续的线性结构,物理上不一定连续,常见的线性表有顺序表、链表、栈、队列……

1.2 顺序表

顺序表是线性表的一种,顺序表一般使用一段连续的地址来存储数据,比如数组。在数组中进行增删查改等操作。

2. 功能实现

顺序表分为静态顺序表(容量有限)和动态顺序表(可扩容),今天我们实现的是动态顺序表,并且能存储任意类型的数据,所以使用到了泛型的知识点,如果不了解泛型的小伙伴可以参考博主之前出的预备知识:
泛型初识

2.1 整体框架

一个顺序表中需要有:数组(用于存放有效数据)、容量、当前数据个数,所以我们定义一个类,成员变量分别是存放数据的数组array、记录当前数据个数的curSize、当前顺序表的容量Capacity(默认是10,可以按需修改)。在构造方法中初始化数组的内容,这样当我们实例化一个顺序表对象后,就能初始化顺序表了。

public class SeqList<T> {
    public Object[] array;//存放数据的数组
    public int curSize;//当前数据个数
    private int Capacity = 10;//容量
    public SeqList() {
    	this.array = new Object[this.Capacity];
    }
}

2.2 乱七八糟的功能(bushi)

2.2.1 判断容量是否满

逻辑很简单,只要判断当前数据个数的curSize是否与顺序表的容量Capacity相等即可,如果满了返回true,没满返回false

    public boolean isFull() {
        return this.curSize == this.Capacity;
    }

2.2.2 返回顺序表当前长度

顺序表当前长度指的是当前数据的个数,直接将curSize返回即可

    //返回当前长度
    public int size() {
        return curSize;
    }

2.2.3 扩容

Arrays.copyOf方法能够实现数组的扩容并且将原有的数据拷贝。这里我们将容量扩大两倍,扩容之后别忘了将数组的容量Capacity也变为两倍

    //扩容
    private void dilatation() {
        this.array = Arrays.copyOf(this.array, 2 * this.Capacity);
        this.Capacity *= 2;
    }

2.2.4 清空整个顺序表

循环遍历顺序表,将每个元素依次置为null,然后将curSize和Capacity置为0

    //清空
    public void clear() {
        for (int i = 0; i < curSize; i++) {
            array[i] = null;
        }
        this.curSize = 0;
        this.Capacity = 0;
    }

2.3 插入数据

插入数据的方式有头插、尾插、在指定位置插入。一般情况下插入数据是尾插,所以我们把尾插和在指定位置插入这两个方法重载,头插方法另外实现一个。

2.3.1 头插数据

注意几个细节:
1.插入前判断容量够不够,如果不够需要扩容
2.如果顺序表中没有元素,直接添加,将数据赋值给0下标位置的元素
3.添加之后将当前数据个数curSize加1

如果顺序表中有数据且容量足够,插入前需将数据整体往后挪动,给第一个空出位置,如图:假设顺序表中有12、23、34、45这四个数据,头插法插入数据99
在这里插入图片描述

    //头插
    public void addFront(T data) {
        //如果满了,扩容
        if (isFull()) {
            dilatation();
        }
        //如果没有元素,直接添加
        if (this.curSize == 0) {
            this.array[0] = data;
            this.curSize++;
            return;
        }

        //开始添加
        int cur = curSize;
        while (cur > 0) {
            array[cur] = array[cur - 1];
            cur--;
        }
        array[0] = data;
        this.curSize++;
    }

2.3.2 尾插数据

插入数据前先判断容量够不够,如果不够,扩容。插入时,直接将curSize下标赋值为插入的数据即可

    //尾插
    public void add(T data) {
        if (isFull()) {
            //如果满了,扩容
            dilatation();
        }
        this.array[curSize] = data;
        this.curSize++;
    }

2.3.3 指定位置插入

指定位置插入,指的是pos位置插入数据

注意几个细节:
1.需要判断pos位置的合法性pos不能小于0,pos不能大于curSize(因为顺序表中的数据是连续的)
2.需要判断容量是否足够,如果不够需要扩容

    //在pos位置添加数据
    public void add(int pos, T data) throws PosNotLegalException {
        //判断pos位置合不合法
        try {
            if (pos < 0 || pos > this.curSize) {
                throw new PosNotLegalException("pos位置不合法");
            }
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        //如果满了,扩容
        if (isFull()) {
            dilatation();
        }
        //开始添加
        int cur = curSize;
        while (cur > pos) {
            array[cur] = array[cur - 1];
            cur--;
        }
        array[pos] = data;
        this.curSize++;
    }

2.4 删除数据

删除顺序表中的某个值key,分为两种,第一种是只删除第一次出现的key,第二种是删除所有的key

2.4.1 删除第一次出现的key

如果遇到了key,将key后面的元素整体往前挪动即可,让后一个位置的值覆盖前一个位置的值

    //移除第一次出现的key
    public void remove(T key) {
        int cur = -1;
        for (int i = 0; i < curSize; i++) {
            if (key.equals(array[i])) {
                cur = i;
                //记录该位置
            }
        }
        if (cur == -1) {
            System.out.println("找不到该元素");
        } else {
            //挪数据
            while (cur < curSize - 1) {
                array[cur] = array[cur + 1];
                cur++;
            }
            this.curSize--;
        }
    }

2.4.2 删除所有的的key

利用双指针算法移除所有的key,例如:在原数组(0,1,2 ,2 ,3, 0, 4 , 2)中移除所有的2。定义一个fast变量和slow变量,如果fast下标的值不等于要删除的值,则将fast下标的值赋值给fast下标;如果fast下标的值等于要删除的值,说明这个值不是我们需要的,这时让fast一个人往前走即可
核心代码:

if(arr[fast]!=key) {
	arr[slow]=arr[fast];
	fast++;
	slow++;
} else {
	fast++;
}

在这里插入图片描述

    //移除所有的key
    public void removeAll(T key) {
        //将所有的key都删除
        int fast = 0;
        int slow = 0;
        while (fast < this.curSize) {
            if (this.array[fast] != key) {
                array[slow] = array[fast];
                fast++;
                slow++;
            } else {
                fast++;
            }
        }
        this.curSize = slow;
    }

2.5 查找数据

2.5.1 判定是否包含某个元素

循环遍历顺序表所有元素,如果找到了该元素,返回true,没找到返回false。需要注意的是:我们实现的是泛型类顺序表,传递的是引用类型,引用类型比较不能使用==,而是使用equals方法

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

2.5.2 查找某个元素对应的位置

循环遍历顺序表所有元素,找到了这个元素就返回下标,没找到则返回-1,该方法只返回第一次出现该元素的位置

    // 查找某个元素第一次出现位置
    public int indexOf(T toFind) {
        int index = -1;
        for (int i = 0; i < curSize; i++) {
            if (toFind.equals(array[i])) {
                index = i;
            }
        }
        return index;
    }

2.5.3 pos位置不合法异常

获取元素前需要判断传的参数pos的合法性,pos不能小于0,pos也不能大于等于当前顺序表个数curSize,如果pos合法,返回pos位置的元素即可。
判断pos位置是否合法,可以通过自定义异常来实现,如果pos不合法,抛出自定义的异常,通过try-catch捕获
定义一个pos位置不合法异常:

public class PosNotLegalException extends RuntimeException {
    public PosNotLegalException(String s) {
        super(s);
    }
    public PosNotLegalException() {
        super();
    }
}

2.5.4 获取pos位置的元素:

判断pos的合法性,如果不合法,抛出异常;如果合法,返回该下标元素即可

    //获取pos位置的元素
    public T get(int pos) {
        try {
            if (pos < 0 || pos >= curSize) {
                throw new PosNotLegalException("pos位置不合法");
            }
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        return (T) array[pos];
    }

2.6 修改数据

修改数据:将pos下标位置修改为指定的值,同样需要判断pos的合法性,如果合法直接将pos下标的值修改即可

    //将pos位置设置为value
    public void set(int pos, T value) {
        if (pos < 0 || pos >= curSize) {
            throw new PosNotLegalException("pos位置不合法");
        }
        array[pos] = value;
    }

3. 全部代码

自定义的异常类(pos位置不合法异常)

public class PosNotLegalException extends RuntimeException {
    public PosNotLegalException(String s) {
        super(s);
    }
    public PosNotLegalException() {
        super();
    }
}

SeqList.java文件

public class SeqList<T> {

    public Object[] array;//存放数据的数组
    public int curSize;//当前数据个数
    private int Capacity = 10;//容量

    //初始化
    public SeqList() {
        this.array = new Object[this.Capacity];
    }

    //扩容
    private void dilatation() {
        this.array = Arrays.copyOf(this.array, 2 * this.Capacity);
        this.Capacity *= 2;
    }

    //尾插
    public void add(T data) {
        if (isFull()) {
            //如果满了,扩容
            dilatation();
        }
        this.array[curSize] = data;
        this.curSize++;
    }

    //在pos位置添加数据
    public void add(int pos, T data) throws PosNotLegalException {
        //判断pos位置合不合法
        try {
            if (pos < 0 || pos > this.curSize) {
                throw new PosNotLegalException("pos位置不合法");
            }
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        //如果满了,扩容
        if (isFull()) {
            dilatation();
        }
        //开始添加
        int cur = curSize;
        while (cur > pos) {
            array[cur] = array[cur - 1];
            cur--;
        }
        array[pos] = data;
        this.curSize++;
    }

    //头插
    public void addFront(T data) {
        //如果满了,扩容
        if (isFull()) {
            dilatation();
        }
        //如果没有元素,直接添加
        if (this.curSize == 0) {
            this.array[0] = data;
            this.curSize++;
            return;
        }

        //开始添加
        int cur = curSize;
        while (cur > 0) {
            array[cur] = array[cur - 1];
            cur--;
        }
        array[0] = data;
        this.curSize++;
    }

    //判断容量是否满
    public boolean isFull() {
        return this.curSize == this.Capacity;
    }

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

    // 查找某个元素对应的位置
    public int indexOf(T toFind) {
        int index = -1;
        for (int i = 0; i < curSize; i++) {
            if (toFind.equals(array[i])) {
                index = i;
            }
        }
        return index;
    }

    //获取pos位置的元素
    public T get(int pos) {
        try {
            if (pos < 0 || pos >= curSize) {
                throw new PosNotLegalException("pos位置不合法");
            }
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        return (T) array[pos];
    }

    //判断是否为空
    public boolean isEmpty() {
        return curSize == 0;
    }

    //将pos位置设置为value
    public void set(int pos, T value) {
        if (pos < 0 || pos >= curSize) {
            throw new PosNotLegalException("pos位置不合法");
        }
        array[pos] = value;
    }

    //移除第一次出现的key
    public void remove(T key) {
        int cur = -1;
        for (int i = 0; i < curSize; i++) {
            if (key.equals(array[i])) {
                cur = i;
                //记录该位置
            }
        }
        if (cur == -1) {
            System.out.println("找不到该元素");
        } else {
            //挪数据
            while (cur < curSize - 1) {
                array[cur] = array[cur + 1];
                cur++;
            }
            this.curSize--;
        }
    }

    //移除所有的key
    public void removeAll(T key) {
        //将所有的key都删除
        int fast = 0;
        int slow = 0;
        while (fast < this.curSize) {
            if (this.array[fast] != key) {
                array[slow] = array[fast];
                fast++;
                slow++;
            } else {
                fast++;
            }
        }
        this.curSize = slow;
    }

    //返回当前长度
    public int size() {
        return curSize;
    }

    //清空
    public void clear() {
        for (int i = 0; i < curSize; i++) {
            array[i] = null;
        }
        this.curSize = 0;
        this.Capacity = 0;
    }
}

今天的内容就到这里,感谢老铁们的点赞、收藏、评论~❤

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

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

相关文章

中国贸易金融跨行交易区块链平台CTFU、区块链福费廷交易平台BCFT、中国人民银行贸易金融区块链平台CTFP、银行函证区块链服务平台BPBC

中国人民银行贸易金融区块链平台CTFP介绍 贸易金融的发展概况及存在的问题 1.1 贸易金融的概况 贸易金融是指商业银行在贸易双方债权债务关系的基础上&#xff0c;为国内或跨国的商品和服务贸易提供的贯穿贸易活动整个价值链、全程全面性的综合金融服务。伴随全球化的进程&a…

基于java+springboot+vue实现的宿舍管理系统(文末源码+Lw+ppt)23-597

摘 要 随着信息时代的来临&#xff0c;过去的传统管理方式缺点逐渐暴露&#xff0c;对过去的传统管理方式的缺点进行分析&#xff0c;采取计算机方式构建宿舍管理系统。本文通过课题背景、课题目的及意义相关技术&#xff0c;提出了一种楼宇信息、宿舍信息、宿舍安排、缺勤信…

使用Python进行自动化测试Selenium与PyTest的结合【第150篇—自动化测试】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 使用Python进行自动化测试&#xff1a;Selenium与PyTest的结合 在软件开发中&#xff0c;自…

数据结构:图的最短路径

目录 一、最短路径的基本概念 二、无权图单源最短路径 三、Dijkstra算法&#xff08;正权图单源&#xff09; 3.1、算法的基本步骤 3.2、算法的实现 3.3、习题思考 3.3.1、网络延迟时间 四、A*算法&#xff08;正权图单源单目标点&#xff09; 4.1、算法的基本概念 4…

web自动化--元素定位之xpath和css

元素定位 xpath绝对路径相对路径案例xpath策略&#xff08;路径&#xff09;案例xpath策略&#xff08;层级、扩展&#xff09;属性层级与属性层级与属性拓展层级与属性综合 csscss选择器&#xff08;id、类、标签、属性&#xff09;id选择器类选择器标签选择器属性选择器案例-…

黄衣老太怒骂,难阻年轻人的热情,苹果CEO库克笑开怀

苹果在中国最大的专卖店在上海静安开业&#xff0c;壮观的排队场景--特别的是排队的大多都是年轻人&#xff0c;凸显出国内消费者对苹果的热情&#xff0c;苹果CEO库克亲自在专门店门口迎客&#xff0c;还与消费者热情拥抱。 不过在苹果静安店开业的当天出现了一个插曲&#xf…

E3S独立出版 | 2024年第二届绿色建筑国际会议(ICoGB 2024)

会议简介 Brief Introduction 2024年第二届绿色建筑国际会议(ICoGB 2024) 会议时间&#xff1a;2024年5月22日-24日 召开地点&#xff1a;意大利米兰 大会官网&#xff1a;www.icogb.org ICoGB 2024由意大利米兰理工大学主办&#xff0c;西安交通大学&#xff0c;葡萄牙米尼奥大…

ubuntu20.04安装 ffmpeg 开发环境

参考&#xff1a;参考1 一些相关软件包&#xff0c;已打包整理好&#xff0c;如下 源码包 1、安装步骤 创建安装目录 sudo mkdir -p /usr/local/ffmpeg/lib 解压源码 tar -jxf ffmpeg-4.3.2.tar.bz2 到指定ffmpeg目录进行配置 cd ffmpeg-4.3.2/ 配置&#xff1a;会报错很多…

对BOM的理解,常见的BOM对象有哪些?(非常详细)

文章目录 一、是什么二、window三、location四、navigator五、screen六、history 一、是什么 BOM (Browser Object Model)&#xff0c;浏览器对象模型&#xff0c;提供了独立于内容与浏览器窗口进行交互的对象 其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退&…

C++ Thread 源码 观后 自我感悟 整理

Thread的主要数据成员为_Thr 里面存储的是线程句柄和线程ID 先看看赋值运算符的移动构造 最开始判断线程的ID是否不为0 _STD就是使用std的域 如果线程ID不为0&#xff0c;那么就抛出异常 这里_New_val使用了完美转发&#xff0c;交换_Val和_New_val的值 _Thr _STD exchange(_…

使用 chezmoi vscode, 管理你的 dotfiles

什么是 dotfiles In Unix-like operating systems, any file or folder that starts with a dot character (for example, /home/user/.config), commonly called a dot file or dotfile. 任何以 . 开头去命名的文件或者目录都可以称为 dotfile, 在 Unix-like 系统一般用的比较…

【生成式AI導論 2024】第5講:訓練不了人工智慧?你可以訓練你自己 (下) — 讓語言彼此合作,把一個人活成一個團隊 (開頭有芙莉蓮雷,慎入)

文章目录 视频简介 视频内容 视频简介 from: https://www.油管.com/watch?vinebiWdQW-4 1,849次观看 2024年3月24日 「把一個人活成一個團隊」是從羅振宇老師 2024 跨年演講聽來的&#xff1a; • AI会不会取代人&#xff1f;看看疾病诊断、挖掘机、美容院、solopreneur的案…

小目标检测篇 | YOLOv8改进之增加小目标检测层(四头检测机制)

前言:Hello大家好,我是小哥谈。小目标检测是计算机视觉领域中的一个研究方向,旨在从图像或视频中准确地检测和定位尺寸较小的目标物体。相比于常规目标检测任务,小目标检测更具挑战性,因为小目标通常具有低分辨率、低对比度和模糊等特点,容易被背景干扰或遮挡。为了解决小…

【IoT新星导航】物联网技术人的发展方向

目录 物联网的概念 下面是我对物联网两个方向的认识&#xff1a; 物联网硬件方向&#xff1a; 一般路线&#xff1a; C语言&#xff1a; 单片机&#xff1a; 嵌入式RTOS&#xff1a; 嵌入式Linux&#xff1a; 物联网软件方向&#xff1a; 一般路线&#xff1a; 编程语言的选…

【Linux】进程的进一步认识

目录 进程的创建 fork函数初步认识 fork函数的返回值 写时拷贝 操作系统怎么知道什么时候要写时拷贝的呢&#xff1f; fork的常规用法 fork调用失败的原因 进程终止 进程的退出场景 进程常见退出方法 正常终止&#xff08;可以通过 echo $? 查看进程退出码&#xff…

Linux 常用命令 1

Tips&#xff1a;终端热键ctrl shift 放大终端窗口的字体 ctrl - 缩小终端窗口的字体 注意区分大小写 查阅命令帮助信息&#xff1a; 1&#xff09;--help command –help(两个减号) 显示command命令的帮助信息 2&#xff09;man man command 查阅command命令的使…

【动手学深度学习】深入浅出深度学习之PyTorch基础

目录 一、实验目的 二、实验准备 三、实验内容 1. 数据操作 2. 数据预处理 3. 线性代数 4. 微积分 5. 自动微分 四、实验心得 一、实验目的 &#xff08;1&#xff09;正确理解深度学习所需的数学知识&#xff1b; &#xff08;2&#xff09;学习一些关于数据的实用…

逆向爬虫技术的进阶应用与实战技巧

前言 在互联网的海洋中&#xff0c;数据是无价的财富。爬虫技术作为获取这些数据的重要手段&#xff0c;一直备受关注。然而&#xff0c;随着网站反爬虫机制的日益完善&#xff0c;简单的爬虫程序已经很难满足我们的需求。因此&#xff0c;掌握爬虫逆向技术&#xff0c;突破反爬…

智慧农业引领未来:数字乡村推动农业现代化与智能化

随着信息技术的飞速发展&#xff0c;数字乡村已成为推动农业现代化与智能化的重要力量。智慧农业作为数字乡村的核心组成部分&#xff0c;正以其独特的优势引领未来农业的发展方向。本文将从智慧农业的内涵、发展现状、面临的挑战以及未来展望等方面&#xff0c;探讨数字乡村如…

初始Java篇(JavaSE基础语法)(2)(逻辑控制)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 目录 逻辑控制 顺序结构 分支结构 if语句 switch 语句 循环结构 while 循环 for 循环 do while 循环 输入输出 输出到控制台 从键盘输入 …
最新文章