ArrayList与顺序表

目录

[一、 顺序表](#一、 顺序表)

二、ArrayList简介

三、ArrayList使用

[3.1 ArrayList的构造](#3.1 ArrayList的构造)

[3.2 ArrayList常见操作](#3.2 ArrayList常见操作)

[3.3 ArrayList的遍历](#3.3 ArrayList的遍历)

[3.4 ArrayList的扩容机制](#3.4 ArrayList的扩容机制)


线性表 :是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列...
线性表在逻辑上 是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

一、 顺序表

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

下面是对顺序表的一些相关操作的实现:

创建接口:

java 复制代码
package myList;

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();

    Boolean isFull();
}

实现接口:

java 复制代码
package myList;

import java.lang.reflect.Array;
import java.util.Arrays;

public class MyArrayList implements IList{
    public int[] elem;
    public int usedSize;
    //顺序表的默认大小
    public static final int DEFAULT_SIZE = 10;
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
    public MyArrayList(int capacity) {
        this.elem = new int[capacity];
    }

    //遍历顺序表中的元素
    @Override
    public void display() {
        for (int i = 0 ;i < usedSize ;i++) {
            System.out.print(this.elem[i]+" ");;
        }
        System.out.println();
    }
    @Override
    public void add(int data) {
        /*if(isFull()) {
            //扩容
            elem= Arrays.copyOf(elem,elem.length*2);
        }*/
        checkCapacity();
        this.elem[usedSize] = data;
        this.usedSize++;
    }

    @Override
    public Boolean isFull() {
        return usedSize==elem.length;
    }

    @Override
    public void add(int pos, int data) {
        /*if(isFull()) {
            //扩容
            elem= Arrays.copyOf(elem,elem.length*2);
        }*/
        try {
            checkPos(pos);
        }catch (PosIllegality e) {
            e.printStackTrace();
            return;
        }
        checkCapacity();
        //1、从最后一个有效元素开始往后移动
        //2、当i<pos结束
        for (int i = usedSize-1;i>=pos;i--) {
            elem[i+1]=elem[i];
        }
        //3、存放元素到pos位置
        elem[pos]=data;
        //4、usedSize++
        usedSize++;
    }
    private void checkCapacity() {
        if(isFull()) {
            //扩容
            elem= Arrays.copyOf(elem,elem.length*2);
        }
    }
    //检查pos的合法性
    private void checkPos(int pos) throws PosIllegality{
        if(pos<0||pos>usedSize) {
            System.out.println("不合法");

            //抛出异常
            throw new PosIllegality("插入元素下标异常:"+pos);
        }
    }
    @Override
    public boolean contains(int toFind) {
        if (isEmpty()) {
            return false;
        }
        for (int i = 0;i<usedSize;i++) {
            if(elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }
    public boolean isEmpty() {
        return usedSize == 0;
    }
    @Override
    public int indexOf(int toFind) {
        if (isEmpty()) {
            return -1;
        }
        for (int i = 0;i<usedSize;i++) {
            if(elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public int get(int pos) throws MyArrayListEmpty{
        checkPosGetAndSet(pos);
        if (isFull()) {
            throw new MyArrayListEmpty("获取指定下标元素时,顺序表为空");
        }
        return elem[pos];
    }
    private void checkPosGetAndSet(int pos) throws PosIllegality{
        if(pos<0||pos>=usedSize) {
            System.out.println("不合法");

            //抛出异常
            throw new PosIllegality("获取指定位置元素异常:"+pos);
        }
    }
    @Override
    public void set(int pos, int value) {
        checkPosGetAndSet(pos);
        elem[pos]=value;
    }

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

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

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


}

下面是MyArrayListEmpty自定义异常:

java 复制代码
public class MyArrayListEmpty extends RuntimeException{

    public MyArrayListEmpty(String msg) {
        super(msg);
    }
}

PosIllegality自定义异常:

java 复制代码
public class PosIllegality extends RuntimeException{

    public PosIllegality(String msg) {
        super(msg);
    }

}

通过以上代码可知,当对顺序表进行插入或删除元素的时候,需要移动大量的数据元素,是比较麻烦的操作,这也是顺序表的一个缺点。

二、ArrayList****简介

在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

三、ArrayList****使用

3.1 ArrayList****的构造

|----------------------------------------|------------------------------|
| 方法 | 解释 |
| ArrayList() | 无参构造 |
| ArrayList(Collection<? extends E> c) | 利用其他 Collection 构建 ArrayList |
| ArrayList(int initialCapacity) | 指定顺序表初始容量 |

代码示例:

java 复制代码
public static void main(String[] args) {
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}

3.2 ArrayList****常见操作

ArrayList虽然提供的方法比较多,常用方法如下所示 :

|-----------------------------------------------|---------------------------|
| 方法 | 解释 |
| boolean add(E e) | 尾插 e |
| void add(int index, E element) | 将 e 插入到 index 位置 |
| boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
| E remove(int index) | 删除 index 位置元素 |
| boolean remove(Object o) | 删除遇到的第一个 o |
| E get(int index) | 获取下标 index 位置元素 |
| E set (int index, E element) | 将下标 index 位置元素设置为 element |
| void clear () | 清空 |
| boolean contains(Object o) | 判断 o 是否在线性表中 |
| int indexOf(Object o) | 返回第一个 o 所在下标 |
| int lastIndexOf(Object o) | 返回最后一个 o 的下标 |
| List<E> subList(int fromIndex, int toIndex) | 截取部分 list |

3.3 ArrayList****的遍历

ArrayList 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器

代码示例:

java 复制代码
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下标+for遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍历
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}

3.4 ArrayList****的扩容机制

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。ArrayList源码中扩容方式:

  1. 检测是否真正需要扩容,如果是调用grow准备扩容

  2. 预估需要库容的大小

  • 初步预估按照1.5倍大小扩容
  • 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
  • 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
  1. 使用 copyOf 进行扩容
    总结:扩容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗。增容一般是呈2 倍的增长,势必会有一定的空间浪费。例如当前容量为 100 ,满了以后增容到 200 ,我们再继续插入了5 个数据,后面没有数据插入了,那么就浪费了 95 个数据空间。对于该问题,我们应该怎样解决呢?
相关推荐
24k小善1 小时前
Flink TaskManager详解
java·大数据·flink·云计算
想不明白的过度思考者1 小时前
Java从入门到“放弃”(精通)之旅——JavaSE终篇(异常)
java·开发语言
.生产的驴1 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
猿周LV1 小时前
JMeter 安装及使用 [软件测试工具]
java·测试工具·jmeter·单元测试·压力测试
晨集1 小时前
Uni-App 多端电子合同开源项目介绍
java·spring boot·uni-app·电子合同
时间之城2 小时前
笔记:记一次使用EasyExcel重写convertToExcelData方法无法读取@ExcelDictFormat注解的问题(已解决)
java·spring boot·笔记·spring·excel
椰羊~王小美2 小时前
LeetCode -- Flora -- edit 2025-04-25
java·开发语言
凯酱2 小时前
MyBatis-Plus分页插件的使用
java·tomcat·mybatis
程序员总部2 小时前
如何在IDEA中高效使用Test注解进行单元测试?
java·单元测试·intellij-idea
oioihoii2 小时前
C++23中if consteval / if not consteval (P1938R3) 详解
java·数据库·c++23