【数据结构】 List与顺序表及接口的实现

简介: 【数据结构】 List与顺序表及接口的实现

什么是List

集合框架中,List是一个接口,继承自Collection。

Collection也是一个接口,该接口中规范了后序容器中常用的一些方法,具体如下所示:

Iterable也是一个接口,表示实现该接口的类是可以逐个元素进行遍历的,具体如下:

List 的官方文档

站在数据结构的角度来看,List就是一个线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删改查以及变量等操作。

常见接口介绍

List中提供了好的方法,具体如下:

虽然方法比较多,但是常用方法如下:

注意:List是个接口,并不能直接用来实例化

线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列…

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储

顺序表

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

在数组上完成数据的增删查改

顺序表接口的实现

我们现在有这样一个SepList接口为:

public interface SepList  {
    // 新增元素,默认在数组最后新增
    void add(int data);
    // 在 pos 位置新增元素
    void add(int pos, int data);
    // 判定是否包含某个元素
    boolean contains(int toFind);
    // 查找某个元素对应的位置
    int indexOf(int toFind);
    // 获取 pos 位置的元素
    int get(int pos);
    // 给 pos 位置的元素设为 value
    void set(int pos, int value);
    //删除第一次出现的关键字key
    void remove(int key);
    // 获取顺序表长度
    int size();
    // 清空顺序表
    void clear();
}

这里博主将在一个MyArrayList类里面实现这些接口

public class MyArrayList implements SepList  {
    private int[] elem;//数组
    private int usedSize;//记录有效的数据的个数
    private static final int DEFAULT_SIZE = 10;//最初的数据容量
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
    // 新增元素,默认在数组最后新增
    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 key) { }
    // 获取顺序表长度
    public int size() { return 0; }
    // 清空顺序表
    public void clear() { }
}

add在末尾新增元素

在增加一个元素前,我们需要对该顺序表进行判断,判断是否已满,若满则需要进行扩容

每增加一个元素,我们我们记录有效个数的usedSize加1

// 新增元素,默认在数组最后新增
    public void add(int data) {
        //判断数组是否已经被装满
        if(usedSize >= this.elem.length) {
            //被装满后需要进行扩容
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        this.elem[this.usedSize] = data;
        usedSize++;
    }

在 pos 位置新增元素

在增加一个元素前,我们需要对该顺序表进行判断,判断是否已满,若满则需要进行扩容

我们还需要多pos进行一个判断,判断它是否合法,如果不合法,我们抛出异常进行提醒

在pos位置增加元素,需要将pos位置及以后的元素进行后移一位,然后再在pos位置新增元素

每增加一个元素,我们我们记录有效个数的usedSize加1

//自定义异常
class PosWrongfulException extends RuntimeException {
    public PosWrongfulException(String message) {
        super(message);
    }
}
 // 在 pos 位置新增元素
    public void add(int pos, int data) throws PosWrongfulException {
        //判断数组是否已经被转满
        if(usedSize >= this.elem.length) {
            //被装满后需要进行扩容
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        if(pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法!");
            throw new PosWrongfulException("pos位置不合法");
        }
        for(int i = this.usedSize;i >= pos;i--) {
            //pos位置以及pos位置以后的数据整体进行后移
            this.elem[i] = this.elem[i-1];
        }
        this.elem[pos] = data;
        usedSize++;
    }

判定是否包含某个元素

遍历即可

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

查找某个元素对应的位置

对数组进行遍历,有的话返回相应的数组下标就好,没有返回-1

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

获取 pos 位置的元素

获取前我们得进行判断,该顺序表类元素不能为空

我们还得对pos进行是否合法得判断

//自定义的异常
class PosWrongfulException extends RuntimeException {
    public PosWrongfulException(String message) {
        super(message);
    }
}
class EmptyException extends RuntimeException {
    public EmptyException(String message) {
        super(message);
    }
}
  // 获取 pos 位置的元素
    public int get(int pos)throws PosWrongfulException {
        if(this.usedSize == 0)
        {
            throw new EmptyException("当前顺序表为空!");
        }
        if(pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法!");
            throw new PosWrongfulException("pos位置不合法");
        }
        return this.elem[pos];
    }

给 pos 位置的元素设为 value

我们依旧需要判断pos的合法性,前面已经自定义了该异常,这里就不再进行定义了

然后将pos位置的元素改为value就好

// 给 pos 位置的元素设为 value
    public void set(int pos, int value) {
        if(pos < 0 || pos > this.usedSize) {
            System.out.println("pos位置不合法!");
            throw new PosWrongfulException("pos位置不合法");
        }
        this.elem[pos] = value;
    }

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

我们依旧需要判断数组是否为空

遍历数组,若没有我们要删除的元素,我们便进行提示后退出

若有,则只需要用后面的数据对前面进行覆盖就好

//删除第一次出现的关键字key
    public void remove(int key) {
        if(this.usedSize == 0) {
            throw new EmptyException("顺序表为空!");
        }
        int index = this.indexOf(key);
        if(index == -1) {
            System.out.println("没有这个数字");
            return;
        }
        //进行覆盖
        for (int i = index; i < size()-1; i++) {
            this.elem[i] = this.elem[i+1];
        }
        //如果不是基本类型,将usedSize下标置为空
        //this.elem[this.usedSize] = null;
        this.usedSize--;
    }

获取顺序表的长度

这个就非常简单了,只需要返回usedSize就好

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

清空顺序表

对于当前基本类型的数据来说,只需要将usedSize置为0就好

public void clear() {
        this.usedSize=0;
    }

顺序表的优缺点

线性表的顺序存储结构,在存、读数据时,不管是哪个位置,时间复杂度都是O(1);而插入或删除时,时间复杂度都是O(n)。这就说明,它比较适合元素个数不太变化,而更多是存取数据的应用。当然,它的优缺点还不只这些……

优点:

无需为表示表中元素之间的逻辑关系而增加额外的存储空间可以快速地存取表中任一位置的元素

缺点:

插入删除操作需要移动大量元素,当线性表长度变化较大时,难以确定存储空间的容量,造成存储空间的碎片

总结

关于《【数据结构】 List与顺序表及接口的实现》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

相关文章
|
2月前
|
存储 编译器 C语言
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
57 2
|
1月前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
1月前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
1月前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
65 3
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
2月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
31 1
|
2月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
40 4
|
2月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
35 6
|
2月前
|
存储
数据结构(顺序表)
数据结构(顺序表)
28 0
|
2月前
|
存储 算法
【数据结构】新篇章 -- 顺序表
【数据结构】新篇章 -- 顺序表
16 0