《Java数据结构入门》顺序表详解

简介: 《Java数据结构入门》顺序表详解

顺序表介绍:

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

🍑顺序表一般可以分为:

  1. 1.静态顺序表:使用定长数组存储元素。(本篇主要围绕静态顺序表展开)
  2. 2.动态顺序表:使用动态开辟的数组存储。


顺序表的手动实现

📝本文将创建两个Java文件:MyArraysList.java用于顺序表的实现,Test.java用于顺序表的各个接口的测试


顺序表功能接口概览

import java.util.Arrays;
public class MyArraysList {
    private int[] elem;
    private int usedSize; // 默认值是0
    private static final int DEFAULT_SIZE = 4; // 定义为常量,更加安全
    // 初始化顺序表
    public MyArraysList() {
        this.elem = new int[4];
    }
    // 对顺序表进行扩容
    public void expand() {}
    //判断当前顺序表是否为空
    public boolean isempty() {}
    // 判断当前顺序表是不是满了
    public boolean isFull() {}
    // 打印顺序表
    public void display() {}
    // 新增元素,默认在数组最后新增
    public void add(int data) {}
    // 新增元素,在数组最前面新增
    public void addHead(int data){}
    // 在 pos 位置新增元素
    public void addPos(int pos, int data) {}
    // 删除表头元素
    public void removeHead() {}
    // 删除表尾元素
    public void removeTail() {}
    // 指定下标元素的删除
    public void removePos(int pos) {}
    //删除第一次出现的关键字key
    public void remove(int toRemove) {}
    // 判定是否包含某个元素
    public boolean contains(int toFind) { return true; }
    // 查找某个元素对应的位置
    public int indexOf(int toFind) { return -1; }
    // 获取 pos 位置的元素
    public int getPos(int pos) { return -1; }
    // 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {}
    // 获取顺序表长度
    public int size() { return 0; }
    // 清空顺序表
    public void clear() {}
}

基本功能的实现

🌰对顺序表进行扩容

// 对顺序表进行扩容
    public void expand() {
        this.elem = Arrays.copyOf(this.elem, this.usedSize * 2);
        System.out.println("已经成功扩容至原来的两倍"); // 给用户提醒
    }

🌰判断顺序表是否为空 

     /**
     * 判断当前顺序表是否为空
     * @return true->空的,false->还没空
     */
    public boolean isempty() {
        if (this.usedSize == 0) {
            return true;
        }
        else return false;
    }

🌰判断顺序表是否已满

    /**
     * 判断当前顺序表是不是满了
     * @return true->满了,false->还没满
     */
    public boolean isFull() {
        if (this.usedSize == this.elem.length) return true;
        else return false;
    }

🌰打印顺序表

// 打印顺序表
// 打印的第一种方式
    public void display() {
        for (int i = 0; i < this.elem.length; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }
// 打印的第二种方式,用Arrays.toString直接打印
    public void display() {
       System.out.println(Arrays.toString(this.elem));
    }

🌰获取顺序表的有效长度

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

🌰清空顺序表

 // 清空顺序表
    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0; // 注意有效数组长度也要清零
    }

四大功能

一、增加数据

🌰头插

 // 新增元素,在数组最前面新增
    public void addHead(int data) {
        if (isFull()) {
            System.out.println("数组满了,需要扩容");
            expand();
        }
        else {
            // 从usedSize下标开始,不会数组越界(此时的elem.length > usedSize)
            for (int i = this.usedSize; i > 0; --i) {
                this.elem[i] = this.elem[i - 1]; // 从后往前挪动数据,为的是给顺序表的表头腾出来
            }
            this.elem[0] = data; // 在顺序表开头插入
            this.usedSize++;    // 数组有效长度加一
        }

🌰尾插

//在数组最后新增
    public void addTail(int data) {
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else this.elem[this.usedSize++] = data;
    }

🌰指定下标插入

  1. 1.判断pos位置是否合法(在顺序表中,数据是连续的,中间不能有空缺)
  2. 2. 判断顺序表是否满了,如果满了,需要扩容
  3. 3. 插入数据(可能需要挪动元素)
// 在 pos 位置新增元素
    public void addPos(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            System.out.println("pos位置不合法"); return;
        }
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else {
            // 如果插入位置在顺序表的中间,要注意挪动元素,从后向前挪动,这样不会造成元素值的覆盖
            for (int i = this.usedSize - 1; i >= pos; --i) {
                this.elem[i + 1] = this.elem[i];
            }
            this.elem[pos] = data; // 挪动完毕,可以赋值插入
            this.usedSize++;      // 当前元素数加一
        }
    }

二、删除数据

🌰头删

 // 删除表头元素
    public void removeHead() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        // 从第一个元素开始,用后面元素的值覆盖掉前面的值,遍历整个数组就相当于把第一个元素用覆盖的方式抹去了
        for (int i = 1; i < this.usedSize; i++) {
            this.elem[i - 1] = this.elem[i];
        }
        this.elem[this.usedSize - 1] = 0; // 现在的最后一个元素是原来的倒数第二个元素, 所以原来的最后一个有效元素要置0
        this.usedSize--; // 不要忘记改变有效数组的长度
    }

🌰尾删

    // 删除表尾元素
    public void removeTail() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        this.elem[this.usedSize - 1] = 0; // 直接将最后一个元素置0就完成了尾删
        this.usedSize--; // 不要忘记改变有效数组的长度
    }

🌰指定下标元素的删除

 // 指定下标元素的删除
    public void removePos(int pos) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos下标不合法");
        }
        else {
            for (int i = pos; i < this.usedSize - 1; ++i) {
                this.elem[i] = this.elem[i + 1]; // 从要删除的下标开始,用后边元素的值覆盖掉前面的值,就完成了删除
            }
            this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
            this.usedSize--;// 删除后不要忘记更改顺序表的有效长度
        }
    }

🌰删除首次出现的指定元素

 //删除第一次出现的关键字key
    public void removeKey(int toRemove) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toRemove) {
                // 注意是this.usedSize - 1,将此时 i 之后的元素统一往前搬移一个位置
                for (int j = i; j < this.usedSize - 1; ++j) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
                this.usedSize--; // 删除后不要忘记更改顺序表的有效长度
                return; // 只删除第一次出现的
            }
        }
    }

三、查找数据

🌰获取指定位置的元素

  1. 1.考虑要获取的位置是否合法
  2. 2.返回指定位置的元素
 // 获取 pos 位置的元素
    public int getPos(int pos) {
        if (pos < 0 || pos >= this.usedSize) { // 注意这里当pos==this.usedSize也是不合法的,因为此时的pos下标所要获取的是顺序表中第usedSize+1个元素
            System.out.println("pos的位置不合法");
            return -1;
        }
        else {
            return this.elem[pos];
        }
    }

🌰获取指定元素所在的位置

 // 查找某个元素所对应顺序表中的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        System.out.println("在数组中没有找到该元素");
        return -1;
    }

🌰查找表中是否包含某个元素

 /**
 * /判定是否包含某个元素
 * @param toFind 要查找的元素
 * @return true->包含, false->不包含
 */
    public boolean contains(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind)  return true;
        }
        return false;
    }

四、修改数据

🍑首先考虑修改的位置是否合法

🍑考虑特殊情况

// 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (pos == this.usedSize) { // 对这种情况要单独处理,此时相等于增加元素
            this.elem[pos] = value;
            this.usedSize++;
        }
        else {
            this.elem[pos] = value;
        }
    }

总代码

📝MyArraysList.java

import java.util.Arrays;
public class MyArraysList {
    private int[] elem;
    private int usedSize; // 默认值是0
    private static final int DEFAULT_SIZE = 4; // 定义为常量,更加安全
    // 初始化顺序表
    public MyArraysList() {
        this.elem = new int[4];
    }
    // 对顺序表进行扩容
    public void expand() {
        this.elem = Arrays.copyOf(this.elem, this.usedSize * 2);
        System.out.println("已经成功扩容至原来的两倍"); // 给用户提醒
    }
    /**
     * 判断当前顺序表是否为空
     * @return true->空的,false->还没空
     */
    public boolean isempty() {
        if (this.usedSize == 0) {
            return true;
        }
        else return false;
    }
    /**
     * 判断当前顺序表是不是满了
     * @return true->满了,false->还没满
     */
    public boolean isFull() {
        if (this.usedSize == this.elem.length) return true;
        else return false;
    }
    // 打印顺序表
    public void display() {
        for (int i = 0; i < this.elem.length; i++) {
            System.out.print(this.elem[i] + " ");
        }
        // System.out.println(Arrays.toString(this.elem));或者用Arrays.toString打印也行
        System.out.println();
    }
    // 新增元素,默认在数组最后新增
    public void addTail(int data) {
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else this.elem[this.usedSize++] = data;
    }
    // 新增元素,在数组最前面新增
    public void addHead(int data) {
        if (isFull()) {
            System.out.println("数组满了,需要扩容");
            expand();
        }
        else {
            // 从usedSize下标开始,不会数组越界(此时的elem.length > usedSize)
            for (int i = this.usedSize; i > 0; --i) {
                this.elem[i] = this.elem[i - 1]; // 从后往前挪动数据,为的是给顺序表的表头腾出来
            }
            this.elem[0] = data; // 在顺序表开头插入
            this.usedSize++;    // 数组有效长度加一
        }
    }
    // 1、判断pos位置是否合法(在顺序表中,数据是连续的,中间不能有空缺)
    // 2、判断顺序表是否满了,如果满了,需要扩容
    // 3、插入数据(可能需要挪作元素)
    // 在 pos 位置新增元素
    public void addPos(int pos, int data) {
        if (pos < 0 || pos > usedSize) {
            System.out.println("pos位置不合法"); return;
        }
        if (isFull()) {
            System.out.println("数组满了需要扩容");
            expand();
        }
        else {
            // 如果插入位置在顺序表的中间,要注意挪动元素,从后向前挪动,这样不会造成元素值的覆盖
            for (int i = this.usedSize - 1; i >= pos; --i) {
                this.elem[i + 1] = this.elem[i];
            }
            this.elem[pos] = data; // 挪动完毕,可以赋值插入
            this.usedSize++;      // 当前元素数加一
        }
    }
    // 删除表头元素
    public void removeHead() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        // 从第一个元素开始,用后面元素的值覆盖掉前面的值,遍历整个数组就相当于把第一个元素用覆盖的方式抹去了
        for (int i = 1; i < this.usedSize; i++) {
            this.elem[i - 1] = this.elem[i];
        }
        this.elem[this.usedSize - 1] = 0; // 现在的最后一个元素是原来的倒数第二个元素, 所以原来的最后一个有效元素要置0
        this.usedSize--; // 不要忘记改变有效数组的长度
    }
    // 删除表尾元素
    public void removeTail() {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        this.elem[this.usedSize - 1] = 0; // 直接将最后一个元素置0就完成了尾删
        this.usedSize--; // 不要忘记改变有效数组的长度
    }
    // 指定下标元素的删除
    public void removePos(int pos) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos下标不合法");
        }
        else {
            for (int i = pos; i < this.usedSize - 1; ++i) {
                this.elem[i] = this.elem[i + 1]; // 从要删除的下标开始,用后边元素的值覆盖掉前面的值,就完成了删除
            }
            this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
            this.usedSize--;// 删除后不要忘记更改顺序表的有效长度
        }
    }
    //删除第一次出现的关键字key
    public void removeKey(int toRemove) {
        if (isempty()) {
            System.out.println("顺序表为空,删除不合法");
            return;
        }
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toRemove) {
                // 注意是this.usedSize - 1,将此时 i 之后的元素统一往前搬移一个位置
                for (int j = i; j < this.usedSize - 1; ++j) {
                    this.elem[j] = this.elem[j + 1];
                }
                this.elem[this.usedSize - 1] = 0; // 要完整的删除,将挪动的最后一个元素的原本位置 置空
                this.usedSize--; // 删除后不要忘记更改顺序表的有效长度
                return; // 只删除第一次出现的
            }
        }
    }
    /**
     * /判定是否包含某个元素
     * @param toFind 要查找的元素
     * @return true->包含, false->不包含
     */
    public boolean contains(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind)  return true;
        }
        return false;
    }
    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if (this.elem[i] == toFind) {
                return i;
            }
        }
        System.out.println("在数组中没有找到该元素");
        return -1;
    }
    // 获取 pos 位置的元素
    public int getPos(int pos) {
        if (pos < 0 || pos >= this.usedSize) {
            System.out.println("pos的位置不合法");
            return -1;
        }
        else {
            return this.elem[pos];
        }
    }
    // 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {
        if (pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法");
            return;
        }
        if (pos == this.usedSize) { // 对这种情况要单独处理,此时相等于增加元素
            this.elem[pos] = value;
            this.usedSize++;
        }
        else {
            this.elem[pos] = value;
        }
    }
    // 获取顺序表长度
    public int size() {
        return this.usedSize;
    }
    // 清空顺序表
    public void clear() {
        for (int i = 0; i < this.usedSize; i++) {
            this.elem[i] = 0;
        }
        this.usedSize = 0; // 注意有效数组长度也要清零
    }
}

🏀测试结果


af065f2d0d4b4217a187e9add3ea15db.png

好了,今天的文章就到这里了,感谢大家的支持🥰,下篇见😁

d936efdb7df741b1b3aceffead5177fb.jpg

相关文章
|
6天前
|
自然语言处理 Java
Java中的字符集编码入门-增补字符(转载)
本文探讨Java对Unicode的支持及其发展历程。文章详细解析了Unicode字符集的结构,包括基本多语言面(BMP)和增补字符的表示方法,以及UTF-16编码中surrogate pair的使用。同时介绍了代码点和代码单元的概念,并解释了UTF-8的编码规则及其兼容性。
78 60
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
61 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
13天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
25天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
42 5
|
1月前
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
2月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
54 6
|
2月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
2月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
2月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
90 5