数据结构之动态数组列表List

学习了一段时间的Java,我们对Java的基本知识有了一定的了解,今天再来聊聊数组。

Java内置数组的特点

  • 数组的长度一旦确定则不可更改

  • 数组只能存储同一类型的数据

  • 数组中每个存储空间大小一致且地址连续

  • 数组提供角标的方式访问元素

我们发现数组又有一些局限性,于是在使用时又会有一些疑惑,我们可以总结一下
Java内置数组的潜在问题

容量不够用时,怎么办?

指定位置插入或删除元素,怎么做?

数组对象只有length属性,能满足更多的需求吗?

动态数组的封装
有了问题,我们就有想法,尝试用学过的知识来解决

能否用面向对象的思想,将数组进行再度封装呢?

可以的,我们可以把数组的相关属性和相关行为封装在类中

类似字符串String类,形成如下的调用形式

String s="HelloWorld";
s.charAt(1);
s.compareTo("Hello");
s.equals("Hello");
s.repalce('l','L');

数组对象.排序()

数组对象.插入(元素)

数组对象.查找(角标)

这样大大方便了我们对数组的操作

那么如何封装动态数组
属性方面:

  • int size 数组的有效元素个数
  • int capacity 数组的最大容量data.length
  • E[] data 数据的存储容器

行为方面:

  • 增()
  • 删()
  • 改()
  • 查()
  • 其他()

为什么要强调动态数组
动态数组是顺序存储结构的具体实现!

1)线性表的定义

零个或多个数据元素的有限序列
在这里插入图片描述2)线性表接口List的定义

在这里插入图片描述
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定

public interface List<E> extends Iterable<E>{
    //获取线性表中元素的有效个数
    int getSize();
    //判断线性表是否为空表
    boolean isEmpty();
    //在线性表指定的index角标处插入元素e
    void add(int index,E e);
    //在线性表的表头处插入元素e
    void addFirst(E e);
    //在线性表的表位处插入元素e
    void addLast(E e);
    //获取线性表中指定角标index处的元素
    E get(int index);
    //获取表头元素
    E getFirst();
    //获取表尾元素
    E getLast();
    //修改线性表中指定角标index处的元素为新元素e
    void set(int index,E e);
    //判断线性表中是否包含元素e
    boolean contains(E e);
    //查找元素e的角标(从左到又默认第一个出现的元素角标)
    int find(E e);
    //删除并返回线性表中指定角标index处的元素
    E remove(int index);
    //删除并返回表头元素
    E removeFirst();
    //删除并返回表尾元素
    E removeLast();
    //删除指定元素e
    void removeElement(E e);
    //清空线性表
    void clear();
}

创建线性表List的顺序存储结构实现类ArrayList

public class ArrayList<E> implements List<E>{
    //创建E类型的一维数组
    private E[] data;
    //维护元素个数
    private int size;
    //默认最大容量为10
    private static int DEFAULT_CAPACITY=10;
    }

先创建一个顺序表 ,重写函数来获取元素有效个数与判断是否为空

//创建一个默认大小的顺序表
    public ArrayList(){
        this(DEFAULT_CAPACITY);
        //data=(E[])(new Object[DEFAULT_CAPACITY]);
    }

    //创建一个容量由用户指定的顺序表
    public ArrayList(int capacity){
        if(capacity<=0) {
            throw new IllegalArgumentException("容量>0:" + capacity);
        }
        data=(E[])(new Object[capacity]);
        size=0;
    }

    //用户传入一个数组 将该数组封装成一个顺序表
    public ArrayList(E[] data){
        if(data==null){
            throw new IllegalArgumentException("数组不能为空");
        }
        this.data=(E[])(new Object[data.length]);
        for (int i = 0; i <data.length ; i++) {
            this.data[i]=data[i];
        }
        size=data.length;
    }

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

    @Override
    public boolean isEmpty() {
        return size==0;
    }

在指定角标插入元素时,如果数组已满,则需要扩容

@Override
    public void add(int index, E e) {
        if(index<0||index>size){
            throw new IllegalArgumentException("角标越界");
        }
        if(size==data.length){
            //扩容
            resize(data.length*2);
        }
        for (int i = size; i >index ; i--) {
            data[i]=data[i-1];
        }
        data[index]=e;
        size++;
    }
	private void resize(int newLength) {
        E[] newData=(E[])(new Object[newLength]);
        for (int i = 0; i < size; i++) {
            newData[i]=data[i];
        }
        data=newData;
    }
    @Override
    public void addFirst(E e) {
        add(0,e);
    }

    @Override
    public void addLast(E e) {
        add(size,e);
    }

获取指定元素位置

    @Override
    public E get(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        return data[index];
    }

    @Override
    public E getFirst() {
        return get(0);
    }

    @Override
    public E getLast() {
        return get(size-1);
    }

修改线性表中指定角标index处的元素为新元素e

    @Override
    public void set(int index, E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        data[index]=e;
    }

查找元素e的角标(从左到又默认第一个出现的元素角标)

    @Override
    public boolean contains(E e) {
        return find(e)!=-1;
    }

在数组中查找是否含有指定元素e

    @Override
    public int find(E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        for (int i = 0; i < size; i++) {
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }

删除并返回线性表中指定角标index处的元素

    @Override
    public E remove(int index) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        E ret=data[index];
        for(int i=index+1;i<size;i++){
            data[i-1]=data[i];
        }
        size--;
        if(size<=data.length/4&&data.length/2>=10){
            resize(data.length/2);
        }
        return ret;
    }

    @Override
    public E removeFirst() {
        return remove(0);
    }

    @Override
    public E removeLast() {
        return remove(size-1);
    }

删除指定元素e

    @Override
    public void removeElement(E e) {
        int index=find(e);
        if(index!=-1){
            remove(index);
        }else{
            throw new IllegalArgumentException("元素不存在");
        }
    }

清空线性表

    @Override
    public void clear() {
        size=0;
        data=(E[])(new Object[DEFAULT_CAPACITY]);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值