数据结构(基于java语言描述)--动态数组

话不多说,让我们先上代码

注:构建数组所存储的元素可能为String、Integer等不同的类型,所以我们有必要设置一个泛型,让数组可以容纳我们调用时所规定的数据类型。

public class Array<E>{

    private E[] data;

    private int size;

    //有参构造函数,传入数组的容量为capacity
    public Array(int capacity) {

        data = (E[])new Object[capacity];    //类型转化
        size = 0;

    }

    //无参构造函数,默认数组容量为10
    public Array() { this(10); }



    //现在可以忽略,在之后的堆的描述中我会讲解
    public Array(E[] arr) {

        data  = (E[]) new Object[arr.length];

        for (int i = 0; i < arr.length; i++){
            data[i] = arr[i];
        }

        size = arr.length;

    }



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


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


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


    //index索引的位置插入新元素
    public void add(int index, E e) {

        //先对索引位置的合法性进行判断
        if ( index < 0 || index > size){
            throw new IllegalArgumentException("add failed, require index >= 0 and index <= size");
        }

        //判断数组是否需要扩容
        if (size == data.length) {
            resize( 2 * data.length);
        }

        //遍历将[indxe, size-1]的元素全部向后移动,在index位置插入新的元素
        for (int i = size - 1; i >= index; i--) {
            data[i+1] = data[i];
        }

        data[index] = e;

        //此时数组的size增加
        size++;

    }


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


    //在所有元素前添加一个元素
    public void addFirst(E e) {add(0, e); }


    //从数组中删除index位置的元素
    public E remove(int index){

        //首先判断删除index是否合理
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("remove failed. index is illegal");
        }

        E ret = data[index];

        //遍历循环,将[index+1, size-1]范围的元素向前移动一位
        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);}


    //修改index索引位置的元素为e
    public void set(int index, E e){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("set failed. index is illegal.");
        }
        data[index] = e;
    }


    //获取index索引的位置
    public E get(int index){
        if (index < 0 || index >= size){
            throw new IllegalArgumentException("set failed. index is illegal.");
        }
        return data[index];
    
}

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

public E getLast(){ return get(size-1);
}
// 查找数组中是否有元素 public boolean contains( E e){ for ( int i = 0 ; i < size ; i++){ if ( data[i].equals(e)){ return true; } } return false; } // 查找数组中元素 e 所在的索引,如果不存在元素 e ,则返回 -1 public int find( E e) { for ( int i = 0 ; i < size ; i++) { if ( data[i].equals(i)) { return i ; } } return - 1 ; } // 从数组中删除元素 e public void removeElement( E e){ int index = find(e) ; if (index != - 1){ remove(index) ; } } // 将数组中的两个指定元素交换 public void swap( int i , int j){ if (i < 0 || i>= size || j < 0 || j >= size){ throw new IllegalArgumentException( "swap failed. index is illegal.") ; } E ret = data[i] ; data[i] = data[j] ; data[j] = ret ; } // 将数组空间容量跟新 private void resize( int newCapacity){ E[] newData = ( E[]) new Object[newCapacity] ; for ( int i = 0 ; i < size ; i++){ newData[i] = data[i] ; } data = newData ; }}

动态数组扩容的问题

上述代码中我们我们给出了如下假设:

    在给data数组添加元素前,如果data数组中的容量和元素个数size相同,扩容为原来的2倍:

    再给data数组删除元素后,如果data数组的size是capacity的1/4,并且capacity不能被2整除


如果我们单纯的将data数组中capacity和size相同时扩容(2倍),小于1/2时缩容(1/2),就会出现这样一个情况:

    当size达到capacity的零界点时,数组扩容到原来的两倍,绕后如果下一个操作是一个删除操作,数组又会瞬间进行缩容,这样反复操作会增加增删操作的时间复杂度,因此我们需要设置一个范围,来给其缓冲。


此时我们数组的复杂度:

add方 : O(n/2)

addLast: O(1)

addFirst: O(n)

remove: (n/2)

removeLast: O(1);

removeFirst: O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值