今天来实现一个Java写的动态数组,就像平时使用的ArrayList一样,当容量不够时可以动态扩容,容量过大时可以动态缩容。
需要的一些方法:
有参构造Array(int capacity)capacity用来指定数组大小
无参构造Array()默认开辟10个对象大小的数组
getSize()getCapacity()isEmpty()判断是否为空
find(E e)查找函数
add(int index,E e)向指定位置添加元素的方法
addFirst(E e)向数组头部添加元素
addLast(E e)向数组尾部添加元素
private resize(int capacity)重新分配数组容量的方法
remove(int index)删除指定位置的元素
removeFirst()删除数组的第一个元素
removeLast()删除数组的最后一个元素
get(int index)获取指定位置的元素
contains(E e)判断数组中是否存在元素e
set(int index,E e)修改指定位置的元素
toString()

package com.yunding.dataStructures;

import java.util.Map;

/**
 * @Author: Lang
 * @Date: 2020/7/4
 * @Description: 动态数组
 */
public class Array<E> {
    private E[] data;
    private int size;

    //构造函数,传入数组的容量capacity构造Array
    public Array(int capacity){
        data = (E[])new Object [capacity];
        size = 0;
    }
    //无参构造,默认数组容量为10
    public Array(){
        this(10);
    }

    //获取数组中的元素个数
    public int getSize(){
        return size;
    }

    //获取数组的容量
    public int getCapacity(){
        return this.data.length;
    }

    //返回数组是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //向所有的元素后添加一个新元素
    public void addLast(E e){
        add(size,e);
    }

    //向数组首地址添加一个新元素
    public void addFirst(E e){
        add(0,e);
    }

    //添加元素
    public void add(int index,E e){
        if(index < 0 || index > size){
            throw new IllegalArgumentException("index<0 or index>size");
        }
        //动态扩容
        if(size == data.length){
            resize(2*data.length);
        }
        for(int i = size-1; i >= index; i--){
            data[i+1] = data[i];
        }
        data[index] = e;
        size ++;
    }

    private void resize(int capacity) {
        E[] newData = (E[]) new Object[capacity];
        for(int i=0;i<size;i++){
            newData[i] = data[i];
        }
        data = newData;
    }

    //从数组中删除index位置的元素,返回删除的元素
    public E remove(int index){
        if(index < 0 || index > size){
            throw new IllegalArgumentException("index<0 or index>size");
        }
        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 != 0){
            resize(data.length/2);
        }
        return ret;
    }

    //删除数组第一个元素
    public E removeFirst(){
        return remove(0);
    }

    //删除数组最后一个元素
    public E removeLast(){
        return remove(size-1);
    }

    //查找指定位置的元素
    public E get(int index){
        return data[index];
    }

    //查询是否包含
    public boolean contains(E e){
        for(int i=0;i<size;i++){
            if(data[i].equals(e)){
                return true;
            }
        }
        return false;
    }

    //修改指定下标的元素,并返回修改前的元素
    public E set(int index,E e){
        if(index < 0 || index > size){
            throw new IllegalArgumentException("index<0 or index>size");
        }
        E e1 = data[index];
        data[index] = e;
        return e1;
    }

    //查找元素并返回元素的下标,如果不存在则返回-1
    public int find(E e){
        for(int i = 0; i < size; i++){
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public String toString(){

        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d \n",size,data.length));
        res.append('[');
        for(int i = 0; i < size; i++){
            res.append(data[i]);
            if(i!=size-1){
                res.append(",");
            }
        }
        res.append(']');
        return res.toString();
    }
}

核心在于add(),remove()和resize()方法,添加方法会在容量不足时重新申请内存扩容,容量达到原来的两倍。
而删除元素当现有元素是数组容量的1/2时并不会立马缩容,因为为防止复杂度震荡,复杂度震荡是什么呢?
当一个数组原有容量为n,当数组满后继续添加元素就会扩容,当再删除一个元素,又进行缩容,再添加元素时又进行扩容,这样就会导致复杂度很高。
所以,为了防止这种情况,删除元素时可以在数组的元素为数组长度的1/4时再进行缩容,这样可以有效避免复杂度震荡。

操作

first

last

一般

添加元素

O(n)

O(1)

O(n/2)=O(n)

删除元素

O(n)

O(1)

O(n/2)=O(n)

修改元素

set(int index,E e)

O(1)

查找元素

get(int index)

contains(E e)

find(E e)

O(1)

O(n)

O(n)