数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题

简介: 文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。

顺序表简介

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

自定义顺序表

    以下是顺序表的类以及相关方法,接下来我将带着你**手把手**地将里面的方法**补充完**并**讲解代码逻辑**,只想看完整源码的下拉到最下面或点击目录中的完整源码,即可直接到对应位置

    首先,此处顺序表我们选择底层是由数组来实现,并定义一个变量存放数组有效元素个数,一个常量用来初始化数组的内存空间
public class SeqList {
    private int[] array;
    private int size;
    // 默认构造方法
    SeqList(){ }
    // 判断是否满了,如果满了,自动扩容
    public void fullResize(){   }
    // 新增元素,默认在数组最后新增
    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() { }
}

SeqList —— 构造方法

定义构造方法,初始化数组长度/空间,长度为上面定义的常量

    // 构造方法,初始化5个空间
    public SeqList(){
        this.elem = new int[DEFAULT_CAPACITY];
    }

display —— 打印顺序表

遍历顺序表,打印每个有效元素

    // 打印顺序表
    public void display(){
        for(int i = 0; i < this.count; i++){
            System.out.print(this.elem[i]+" ");
        }
        System.out.println();
    }

fullResize —— 判断是否满了,满了则扩容

判断是否满了,如果满了,自动扩容

    // 判断是否满了,如果满了,自动扩容
    public void fullResize(){
        if(this.elem.length == count){
            elem = Arrays.copyOf(elem, 2*elem.length);
        }
    }

add —— 新增元素,默认在数据最后

    新增元素,**默认在数据最后**,add执行开始,先调用fullResize判断顺序表是否满了,满了则先扩容,再添加元素,因为满了的情况下,没有位置可添加元素
    // 新增元素,默认在数据最后
    public void add(int data){
        fullResize();
        elem[count] = data;
        count++;
    }

add —— 在任意位置新增元素

    **在pos位置新增元素**,先判断pos是否合法,比如插入下标位置为-1或超出数组有效元素个数范围,那肯定不合法,不合法即抛出异常,这里的异常是**我们自己定义的**,目录中点击 **自定义异常类** 即可跳转,也可手动往下翻看

如果合法则挪动数据并插入

为什么有两个add?

这里属于方法的重载,会根据传递的参数自动选择对应的add方法

    // 在 pos 位置新增元素
    public void add(int pos, int data){
        fullResize();
        if(pos < 0 || pos > this.count){
            throw new PosOutBoundsException("add 数据时,位置不合法!");
        }
        // 挪动数据
        for(int i = this.count; i > pos; i--){
            this.elem[i] = this.elem[i-1];
        }
        // 存数据
        this.elem[pos] = data;
        this.count++;
    }

contains —— 判断是否包含某个元素

遍历顺序表,依次比较

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

indexOf —— 查找某个元素对应的位置下标

    // 查找某个元素对应的位置下标
    public int indexOf(int toFind){
        for (int i = 0; i < this.count; i++) {
            if(toFind == this.elem[i]){
                return i;
            }
        }
        return -1;  // 表示没有该元素
    }

checkPos —— 判断参数是否合法

此处的是否合法范围的右边界是按有效元素个数来计算的

    // 判断参数是否合法(按有效元素算)
    public boolean checkPos(int pos){
        if(pos < 0 || pos >= this.count){
            return false;
        }
        return true;
    }

get —— 获取 pos 位置的元素

如果pos不合法,则抛出异常

    // 获取pos位置的元素
    public int get(int pos){
        if(!checkPos(pos)){
            throw new PosOutBoundsException("get 数据时,位置不合法!");
        }
        return this.elem[pos];
    }

set —— 修改/更新元素

给pos位置的元素设置为value [修改/更新]

    // 给pos位置的元素设置为value [修改、更新]
    public void set(int pos, int value){
        if(!checkPos(pos)){
            throw new PosOutBoundsException("set 数据时,位置不合法! ");
        }
        this.elem[pos] = value;
    }

size —— 获取顺序表的长度

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

remove —— 删除第一次出现的关键字key

    // 删除第一次出现的关键字key
    public void remove(int toRemove){
        // 如果列表为空,直接返回
        if(this.count == 0){
            return;
        }
        int index = indexOf(toRemove);
        if(index == -1){
            return;  //没有要删除的关键字
        }
        for(int i = index; i < this.count-1; i++){
            this.elem[i] = this.elem[i+1];
        }
        this.count--;
    }

clear —— 清空顺序表

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

自定义顺序表全部代码

下面的代码在上面都有,只是下面将其完整的展示了出来,供您更有效地复制和阅读代码

友情提示:下面中的 PosOutBoundsException 是我们自定义的异常,目录中点击 自定义异常类 即可跳转,也可手动往下翻看

import java.util.Arrays;

// 顺序表
public class SeqList {
    private int[] elem;
    private int count;   // 计算当前存储有效元素个数

    private static final int DEFAULT_CAPACITY = 5;  // 初始化内存空间

    // 构造方法,初始化5个空间
    public SeqList(){
        this.elem = new int[DEFAULT_CAPACITY];
    }

    // 打印顺序表
    public void display(){
        for(int i = 0; i < this.count; i++){
            System.out.print(this.elem[i]+" ");
        }
        System.out.println();
    }

    // 判断是否满了,如果满了,自动扩容
    public void fullResize(){
        if(this.elem.length == count){
            elem = Arrays.copyOf(elem, 2*elem.length);
        }
    }
    // 新增元素,默认在数据最后
    public void add(int data){
        fullResize();
        elem[count] = data;
        count++;
    }


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

    // 查找某个元素对应的位置下标
    public int indexOf(int toFind){
        for (int i = 0; i < this.count; i++) {
            if(toFind == this.elem[i]){
                return i;
            }
        }
        return -1;  // 表示没有该元素
    }

    // 判断参数是否合法(按有效元素算)
    public boolean checkPos(int pos){
        if(pos < 0 || pos >= this.count){
            return false;
        }
        return true;
    }

    // 获取pos位置的元素
    public int get(int pos){
        if(!checkPos(pos)){
            throw new PosOutBoundsException("get 数据时,位置不合法!");
        }
        return this.elem[pos];
    }

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

    // 给pos位置的元素设置为value [修改、更新]
    public void set(int pos, int value){
        if(!checkPos(pos)){
            throw new PosOutBoundsException("set 数据时,位置不合法! ");
        }
        this.elem[pos] = value;
    }

    // 在 pos 位置新增元素
    public void add(int pos, int data){
        fullResize();
        if(pos < 0 || pos > this.count){
            throw new PosOutBoundsException("add 数据时,位置不合法!");
        }
        // 挪动数据
        for(int i = this.count; i > pos; i--){
            this.elem[i] = this.elem[i-1];
        }
        // 存数据
        this.elem[pos] = data;
        this.count++;
    }

    // 删除第一次出现的关键字key
    public void remove(int toRemove){
        // 如果列表为空,直接返回
        if(this.count == 0){
            return;
        }
        int index = indexOf(toRemove);
        if(index == -1){
            return;  //没有要删除的关键字
        }
        for(int i = index; i < this.count-1; i++){
            this.elem[i] = this.elem[i+1];
        }
        this.count--;
    }


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

自定义异常类

单独定义一个.Java文件存写该代码

    用来在下标不合法等情况下抛出异常,第二个构造方法的意思是抛出异常时会打印出message中的信息
// 自定义异常类
public class PosOutBoundsException extends RuntimeException{
    public PosOutBoundsException(){

    }

    public PosOutBoundsException(String message){
        super(message);
    }
}

自定义顺序表的测试用例

    此段代码用来验证我们写的自定义顺序表是否正确以及功能完整程度,从测试可以看出我们写的代码非常Good
public class Main {
    public static void main(String[] args) {
//        SeqList seqList = new SeqList();
//        for(int i = 0; i < 10; i++){
//            seqList.add(i,i*10);
//        }
//        seqList.display();

        SeqList list = new SeqList();

        // 添加元素并打印列表
        list.add(1);
        list.add(2);
        list.add(3);
        list.display(); // 应该打印 "1 2 3 "

        // 判断是否包含某个元素
        System.out.println(list.contains(2)); // 应该打印 true
        System.out.println(list.contains(4)); // 应该打印 false

        // 查找元素的位置下标
        System.out.println(list.indexOf(3)); // 应该打印 2
        System.out.println(list.indexOf(4)); // 应该打印 -1

        // 获取元素
        System.out.println(list.get(0)); // 应该打印 1
        System.out.println(list.get(2)); // 应该打印 3

        // 获取列表长度
        System.out.println(list.size()); // 应该打印 3

        // 设置元素
        list.set(1, 5);
        list.display(); // 应该打印 "1 5 3 "

        // 在指定位置插入元素
        list.add(1, 4);
        list.display(); // 应该打印 "1 4 5 3 "

        // 删除第一次出现的元素
        list.remove(4);
        list.display(); // 应该打印 "1 5 3 "

        // 清空列表
        list.clear();
        list.display(); // 应该打印空行
        System.out.println(list.size()); // 应该打印 0
    }
}

控制台输出结果如下:(完全正确)

Java中自带的顺序表 —— ArrayList

📜ArrayList简介及使用全方位手把手教学(带源码),用ArrayList实现洗牌算法,3个人轮流拿牌(带全部源码)

🧸至此,感谢您阅读这篇博客,祝您生活愉快! o (ˉ▽ˉ;)

目录
相关文章
|
25天前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
164 1
|
2月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
293 0
|
5月前
|
人工智能 安全 JavaScript
Java ArrayList:动态数组
本文探讨Java中的数组,对比C/C++、JS/PHP/Python等语言的数组特性。文章分析了Java数组的定义、创建方式及其规范,指出其优缺点。Java数组作为引用类型,在堆上分配内存,支持动态大小,避免了C/C++中裸数组的常见问题(如越界访问)。然而,Java数组也存在性能瓶颈和设计缺陷,例如运行时的安全检查影响速度,无法创建超大数组或泛型数组,且多线程场景下缺乏同步机制。作者建议在实际开发中用集合替代数组以规避这些问题。
123 1
|
1月前
|
人工智能 边缘计算 搜索推荐
AI产品测试学习路径全解析:从业务场景到代码实践
本文深入解析AI测试的核心技能与学习路径,涵盖业务理解、模型指标计算与性能测试三大阶段,助力掌握分类、推荐系统、计算机视觉等多场景测试方法,提升AI产品质量保障能力。
|
3月前
|
Java 索引
Java ArrayList中的常见删除操作及方法详解。
通过这些方法,Java `ArrayList` 提供了灵活而强大的操作来处理元素的移除,这些方法能够满足不同场景下的需求。
417 30
|
3月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
86 1
|
3月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
158 0
|
4月前
|
测试技术 Go 开发者
如何为 gRPC Server 编写本地测试代码
本文介绍了如何使用 Go 语言中的 gRPC 测试工具 **bufconn**,通过内存连接实现 gRPC Server 的本地测试,避免端口冲突和外部依赖。结合示例代码,讲解了初始化内存监听、自定义拨号器及编写测试用例的完整流程,并借助断言库提升测试可读性与准确性。适用于单元及集成测试,助力高效开发。
64 1
|
3月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
100 0

热门文章

最新文章