顺序表的实现(ArrayList)

一、什么是顺序表?

顺序表是一种线性存储结构(线性表),其是由一段物理地址连续的存储单元构成的,通常我们采用数组存储,在数组上完成数据的增删改查。

如下图所示:


二、模拟实现ArrayList

  • 创建MyArrayList类,并创建类中元素

//使用泛型类,方便存放各种类型的值
public class MyArrayList<T> {
    //定义一个静态常量为默认数组初始大小
    private static final int DEFAULT_CAPACITY = 10;
    //创建一个Object数组
    private Object[] element = new Object[DEFAULT_CAPACITY];
    //定义一个计数器,方便知道顺序表中已经存放了多少个值
    private int usedSize;
}

  • 建立构造方法

    //有参构造方法,自定义初始容量
    public MyArrayList(int initCapacity){
        element = new Object[initCapacity];
    }

    //无参构造方法,初始容量为默认值
    public MyArrayList(){

    }

  • 插入元素(add)

    //1、尾插
    public void add(T t){
        //判断数组是否已满,已满则扩容
        if(isFull()){
            expandCapacity();
        }

        //插入元素,计数器加1
        element[usedSize] = t;
        usedSize++;
    }

    //2、在指定位置插入元素
    public void add(int index, T t){
        //判断下标是否越界,越界则引发异常
        if(index > usedSize || index < 0){
            new IndexOutOfBoundException(index + "下标越界");
        }

        //判断数组是否已满,已满则扩容
        if(isFull()){
            expandCapacity();
        }

        //将需插入下标后的元素后移,再放入待添加元素
        for (int i = usedSize - 1; i >= index; i--) {
            element[i + 1] = element[i];
        }
        element[index] = t;
        usedSize++;
    }

  • 获取指定下标元素(get)

    //获取所给下标的元素
    public T get(int index){
        //判断下标是否合法,不合法则引发下标越界异常
        if(index >= usedSize || index < 0){
            new IndexOutOfBoundException(index + "下标越界");
        }
        
        //返回该元素
        return (T)element[index];
    }

  • 更改指定下标元素(set)

    //更改指定下标的元素
    public void set(int index, T t){
        //判断下标是否合法,不合法则引发异常
        if(index >= usedSize || index < 0){
            new IndexOutOfBoundException(index + "下标越界");
        }

        //更改该下标元素
        element[index] = t;
    }

  • 判断是否包含指定元素(contain)

    //判断是否包含指定元素
    public boolean contain(T t){
        //for循环逐个对比
        for (int i = 0; i < usedSize; i++) {

            //找到了返回true
            if(element[i].equals(t)){
                return true;
            }
        }

        //没找到则返回false
        return false;
    }

  • 获取指定元素下标(IndexOf)

    //获取第一个与指定元素相同的元素的下标
    public int indexOf(T t){
        //循环对比
        for (int i = 0; i < usedSize; i++) {

            //找到则返回该元素下标
            if(element[i].equals(t)){
                return i;
            }
        }

        //没找到返回-1(因为-1不可能是任何元素的下标)
        return -1;
    }

  • 移除元素(remove)

    //1、去除指定下标元素
    public void remove(int index){

        //判断下标是否越界,越界则引发下标越界异常
        if(index >= usedSize || index < 0){
            new IndexOutOfBoundException(index + "下标越界");
        }

        //将所去除元素后的元素后移,填补空缺
        for (int i = index + 1; i < usedSize; i++) {
            element[i - 1] = element[i];
        }

        //将最后下标位置的值置为null,并将计数器-1
        element[usedSize - 1] = null;
        usedSize--;
    }

    //2、去除与指定元素相同的第一个元素
    public void remove(T t){
        //利用indexOf方法找到其下标
        int index = indexOf(t);

        //若无相同元素则不做任何操作
        if(index == -1){
            return;
        }

        //若找到则使用第一个remove去除该元素
        remove(index);
    }

 

  • 返回已存元素个数(size)

    public int size(){
        //返回计数器usedSize
        return usedSize;
    }

  • 清空顺序表(clear)

    public void clear(){
        //循环将所有已存元素置为null
        for (int i = 0; i < usedSize; i++) {
            element[i] = null;
        }

        //将计数器置为0
        usedSize = 0;
    }

  • 重写toString方法

    //方便可以使用print直接将顺序表打印出来
    @Override
    public String toString() {
        //设置空字符串ret
        String ret = "";

        //循环将每个元素字符化后添入ret中
        for (int i = 0; i < size(); i++) {
            if (i == 0){
                ret = ret + element[i].toString();
            }else {
                ret = ret + ", " + element[i].toString();
            }
        }

        //返回ret
        return "[" + ret + "]";
    }

注意:此处为顺序表的模拟实现,并非与ArrayList类一致。


三、ArrayList的优势和缺陷

  • 优势

在获取或更改某个元素时,可以直接使用下标访问,时间复杂度为O(1)

  • 缺陷

  1. 当插入或删除某个元素时,需要将后续所有元素前移或后移,故时间复杂度为O(n)。
  2. 当扩容时,需要申请新空间,拷贝数据,释放旧空间,会有不少的消耗。
  3. 一般扩容是以2倍或1.5倍扩容,每次add的个数不多,一般会有多余空间浪费。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值