数据结构 模拟实现ArrayList顺序表

简介: 数据结构 模拟实现ArrayList顺序表



一、顺序表中的接口

代码如下:

public interface IList {
    // 新增元素,默认在数组最后新增
    public void add(int data);
    // 在 pos 位置新增元素
    public void add(int pos, int data);
    // 判定是否包含某个元素
    public boolean contains(int toFind);
    // 查找某个元素对应的位置
    public int indexOf(int toFind);
    // 获取 pos 位置的元素
    public int get(int pos);
    // 给 pos 位置的元素设为 value
    public void set(int pos, int value);
    //删除第一次出现的关键字key
    public void remove(int toRemove);
    // 获取顺序表长度
    public int size();
    // 清空顺序表
    public void clear();
    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display();
}

以上的方法就是我们要模拟实现顺序表的方法了。


二、顺序表中的方法实现

创建一个类,这个类实现上面接口,重写类里所有的方法。

我们知道,顺序表其实就是数组,所以要创建一个数组来存放数据,还要用一个整型变量来记录顺序表的大小,还有构造方法,我们可以指定顺序表的容量,也可以使用默认容量为10,代码如下

public class MyArrayList implements IList{
    public int[] elem;
    private int usedSize = 0;
    private int DEFAULT_SIZE = 10;
    public MyArrayList() {
        elem = new int[DEFAULT_SIZE];
    }
    public MyArrayList(int size) {
        elem = new int[size];
    }
}

(1)display方法

这个方法是打印顺序表的方法,并不是顺序表中的方法

@Override
    public void display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.print(elem[i] + " ");
        }
        System.out.println();
    }

(2)add方法

1、不指定下标位置插入

插入元素前要检查顺序表满没满,满了就要扩容,再插入元素,因为没指定下标插入元素,所以插入的是顺序表的末位置,也就是usedSize位置,插入完后usedSize要自增,表示顺序表多了一个元素,代码如下:

@Override
    public void add(int data) {
        //检查容量
        checkCapacity();
        //添加元素
        elem[usedSize] = data;
        usedSize++;
    }
    private void checkCapacity() {//检查容量
        if(ifFull()) {
            //扩容
            elem = Arrays.copyOf(elem, elem.length * 2);
        }
    }
    private boolean ifFull() {//判断数组满了没
        return usedSize == elem.length;
    }

2、指定下标位置插入

指定下标位置插入元素就要判断这个下标是否合法,不合法就要抛出异常,下标是合法的就判断顺序表的容量满了没,没满就扩容,当经过上面两个检查后,才能指定位置插入元素,但插入前,还要把指定的下标,及之后的元素都往后移动一位,才能把要放的元素放进去,代码如下:

@Override
    public void add(int pos, int data) throws PosIllegality{
        //判断pos下标是否合法
        try {
            checkPosOnAdd(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        //数组满了就要扩容
        checkCapacity();
        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }
    private void checkPosOnAdd(int pos) throws PosIllegality{
        if(pos < 0 || pos > usedSize) {
            //不合法,抛异常
            System.out.println("不合法");
            throw new PosIllegality("数组下标不合法" + pos);
        }
    }
//异常
public class PosIllegality extends RuntimeException{
    public PosIllegality(String msg) {
        super(msg);
    }
}

(3)contains方法

判定是否包含某个元素,代码如下:

@Override
    public boolean contains(int toFind) {
        if(usedSize == 0) return false;
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

(4)indexOf方法

查找某个元素对应的位置,代码如下:

@Override
    public int indexOf(int toFind) {
        if(usedSize == 0) return -1;
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

(5)get方法

获取 pos 位置的元素,这个和add指定位置一样,要判断pos下标是否合法,不合法就要抛异常,当顺序表是空的时候,也要抛异常,当上面两个判断都没有抛异常后,就返回指定下标的元素,代码如下:

@Override
    public int get(int pos) {
        try {
            checkPosOnGetAndSet(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        if(usedSize == 0) {
            //数组为空,拿不了,抛异常
            throw new MyArrayListEmpty("顺序表为空");
        }
        return elem[pos];
    }
    private void checkPosOnGetAndSet(int pos) throws PosIllegality{
        if(pos < 0 || pos >= usedSize) {
            //下标不合法
            System.out.println("下标不合法");
            throw new PosIllegality("查找的下标不合法" + pos);
        }
    }
//异常
public class MyArrayListEmpty extends RuntimeException{
    public MyArrayListEmpty(String msg) {
        super(msg);
    }
}

(6)set方法

给 pos 位置的元素设为 value,要检查下标是否合法,不合法就要抛异常,合法就给 pos 位置的元素设为 value,代码如下:

@Override
    public void set(int pos, int value) throws PosIllegality{
        try {
            //检查下标合法性
            checkPosOnGetAndSet(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        elem[pos] = value;
    }

(7)remove方法

删除第一次出现的关键字key,这个方法可以用上面的indexOf方法,找到key值的下标,有就返回下标数字,没有返回-1,当返回的是-1,就输出“没有这个数字”,有就删除这个下标元素,方法是后面元素往前覆盖,再把usedSize自减,表示顺序表少了一个元素,代码如下:

@Override
    public void remove(int toRemove) {
        int index = indexOf(toRemove);
        if(index == -1) {
            System.out.println("没有这个数字");
            return;
        }
        for (int i = index; i < usedSize; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
    }

(8)size方法

获取顺序表长度,代码如下:

@Override
    public int size() {
        return usedSize;
    }

(9)clear方法

清空顺序表,代码如下

@Override
    public void clear() {
        usedSize = 0;
    }

三、最终代码

MyArrayList类:

public class MyArrayList implements IList{
    public int[] elem;
    private int usedSize = 0;
    private int DEFAULT_SIZE = 10;
    public MyArrayList() {
        elem = new int[DEFAULT_SIZE];
    }
    public MyArrayList(int size) {
        elem = new int[size];
    }
    @Override
    public void add(int data) {
        //检查容量
        checkCapacity();
        //添加元素
        elem[usedSize] = data;
        usedSize++;
    }
    private void checkCapacity() {//检查容量
        if(ifFull()) {
            //扩容
            elem = Arrays.copyOf(elem, elem.length * 2);
        }
    }
    private boolean ifFull() {//判断数组满了没
        return usedSize == elem.length;
    }
    @Override
    public void add(int pos, int data) throws PosIllegality{
        //判断pos下标是否合法
        try {
            checkPosOnAdd(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        //数组满了就要扩容
        checkCapacity();
        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }
    private void checkPosOnAdd(int pos) throws PosIllegality{
        if(pos < 0 || pos > usedSize) {
            //不合法,抛异常
            System.out.println("不合法");
            throw new PosIllegality("数组下标不合法" + pos);
        }
    }
    @Override
    public boolean contains(int toFind) {
        if(usedSize == 0) return false;
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }
    @Override
    public int indexOf(int toFind) {
        if(usedSize == 0) return -1;
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }
    @Override
    public int get(int pos) {
        try {
            checkPosOnGetAndSet(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        if(usedSize == 0) {
            //数组为空,拿不了,抛异常
            throw new MyArrayListEmpty("顺序表为空");
        }
        return elem[pos];
    }
    private void checkPosOnGetAndSet(int pos) throws PosIllegality{
        if(pos < 0 || pos >= usedSize) {
            //下标不合法
            System.out.println("下标不合法");
            throw new PosIllegality("查找的下标不合法" + pos);
        }
    }
    @Override
    public void set(int pos, int value) throws PosIllegality{
        try {
            //检查下标合法性
            checkPosOnGetAndSet(pos);
        } catch (PosIllegality e) {
            e.printStackTrace();
        }
        elem[pos] = value;
    }
    @Override
    public void remove(int toRemove) {
        int index = indexOf(toRemove);
        if(index == -1) {
            System.out.println("没有这个数字");
            return;
        }
        for (int i = index; i < usedSize; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
    }
    @Override
    public int size() {
        return usedSize;
    }
    @Override
    public void clear() {
        usedSize = 0;
    }
    @Override
    public void display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.print(elem[i] + " ");
        }
        System.out.println();
    }
}

//异常类

public class MyArrayListEmpty extends RuntimeException{
    public MyArrayListEmpty(String msg) {
        super(msg);
    }
}
public class PosIllegality extends RuntimeException{
    public PosIllegality(String msg) {
        super(msg);
    }
}
相关文章
|
1月前
|
存储 编译器 C语言
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
数据结构-顺序表详解(看这篇就足够了,哈哈哈)
49 2
|
14天前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
17天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
17天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
49 3
|
17天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
1月前
|
Java C++ 索引
让星星⭐月亮告诉你,LinkedList和ArrayList底层数据结构及方法源码说明
`LinkedList` 和 `ArrayList` 是 Java 中两种常见的列表实现。`LinkedList` 基于双向链表,适合频繁的插入和删除操作,但按索引访问元素效率较低。`ArrayList` 基于动态数组,支持快速随机访问,但在中间位置插入或删除元素时性能较差。两者均实现了 `List` 接口,`LinkedList` 还额外实现了 `Deque` 接口,提供了更多队列操作。
23 3
|
1月前
|
存储 缓存 索引
从底层数据结构和CPU缓存两方面剖析LinkedList的查询效率为什么比ArrayList低
本文详细对比了ArrayList和LinkedList的查询效率,从底层数据结构和CPU缓存两个方面进行分析。ArrayList基于动态数组,支持随机访问,查询时间复杂度为O(1),且CPU缓存对其友好;而LinkedList基于双向链表,需要逐个节点遍历,查询时间复杂度为O(n),且CPU缓存对其帮助不大。文章还探讨了CPU缓存对数组增删操作的影响,指出缓存主要作用于读取而非修改。通过这些分析,加深了对这两种数据结构的理解。
35 2
|
1月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
30 6
|
1月前
|
设计模式 安全 容器
数据结构第一篇【探究List和ArrayList之间的奥秘 】
数据结构第一篇【探究List和ArrayList之间的奥秘 】
23 5
|
1月前
|
存储
数据结构(顺序表)
数据结构(顺序表)
23 0

热门文章

最新文章