【数据结构】 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月前
|
消息中间件 NoSQL Redis
redis数据结构-List
redis数据结构-List
33 1
|
10天前
|
数据采集 JavaScript 前端开发
使用 TypeScript 接口优化数据结构
使用 TypeScript 接口优化数据结构
|
6天前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
|
16天前
|
存储 Java 程序员
【数据结构】初识集合&深入剖析顺序表(Arraylist)
Java集合框架主要由接口、实现类及迭代器组成,包括Collection和Map两大类。Collection涵盖List(有序、可重复)、Set(无序、不可重复),Map则由键值对构成。集合通过接口定义基本操作,具体实现由各类如ArrayList、HashSet等提供。迭代器允许遍历集合而不暴露其实现细节。List系列集合元素有序且可重复,Set系列元素无序且不可重复。集合遍历可通过迭代器、增强for循环、普通for循环及Lambda表达式实现,各有适用场景。其中ArrayList实现了动态数组功能,可根据需求自动调整大小。
28 11
|
24天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
24天前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
2月前
|
存储 算法
【数据结构与算法】顺序表
【数据结构与算法】顺序表
17 0
【数据结构与算法】顺序表
|
2月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
2月前
|
存储 测试技术
【初阶数据结构篇】顺序表的实现(赋源码)
线性表(linearlist)是n个具有相同特性的数据元素的有限序列。
|
2月前
|
存储 编译器
【数据结构】顺序表(长期维护)
【数据结构】顺序表(长期维护)
下一篇
无影云桌面