数据结构——动态数组

数据结构
一、动态数组
1.重写Array类:
public class Array {

private T[] data;
private int size;

//构造函数
public  Array(int capacity){
    data = (T[]) new Object[capacity];
    size=0;
}

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

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

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

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

//添加元素到数组末尾
public void addLast(T e){
    add(size,e);
}

//添加元素到数组开头
public void addFirst(T e){
    add(0,e);
}

//向数组中指定位置添加元素
public void add(int index,T e){

    if(index <0||index >size)
        throw new IllegalArgumentException("add is failed, index should >=0 and <=size");

    if(size == data.length)
        **//throw new IllegalArgumentException("add is failed, Array is full");**
        //如果数组容量不够,不抛出异常,再分配一次空间,实现动态数组的目的
        resize(2 * data.length);
    for(int i = size-1;i >=index;i --)
        data[i+1] = data[i];

    data[index] = e;
    size++;
}

//取得给定下标对应的值
public T get(int index){
    if(index<0||index>=size)
        throw new IllegalArgumentException("get is failed, index should >=0 and <size");
    return data[index];
}

//替换或添加元素
public void set(int index,T e){
    if(index<0||index>=size)
        throw new IllegalArgumentException("set is failed, index should >=0 and <size");
    data[index] = e;
}

//判断数组中是否包含给定的值
public boolean contain(T e){
    for(int i=0;i<size;i++){
        if(data[i].equals(e))
            return true;
    }
    return false;
}

//寻找数组中是否有给定值,并返回其下标,如果没有,则返回-1
public int find(T e){
    for(int i=0;i<size;i++){
        if(data[i].equals(e))
            return i;
    }
    return -1;
}

//从数组中删除给定下标对应的元素
public T remove(int index){
    if(index<0||index>=size)
        throw new IllegalArgumentException("index is illegal");
    T res=data[index];
    for(int i=index+1;i<size;i++){
        data[i-1]=data[i];
    }
    size--;
    data[size]=null;//不这样做也是可以的,因为下标为size的元素用户访问不到
    if(size == data.length/4 && data.length/2 != 0)//缩容不能过急,以免在有些情况下导致不断地重新分配空间
        resize(data.length/2);

    return res;
}

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

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

//删除指定元素
public void removeElement(T e){
    int index=find(e);
    if(index!=-1)
        remove(index);
}

//将数组内容转换为字符串
@Override//在重写toString这个方法出错是会报错
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();
}

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

}

2.使用泛型
可以修改这个Array类,使其不仅限于存储整型数据
注意:
泛型不可以是基本数据类型,如int、boolean
编写构造函数时,先将数组定义为Object类的,在将其转换为我们需要的类类型
(Object类是所有类的父类)
==运算符比较的是地址的引用,改成泛型后,要用equals方法判断元素是否相等

3.时间复杂度的分析

3.1简单的时间复杂度分析
O:运行时间和输入数据之间的关系(渐进时间复杂度)
O(n):线性关系
O(n^2):T=knn+b

addLast函数时间复杂度为O(1),因为只是添加了一个元素,其它数据没有变化
addFirst函数时间复杂度为O(n),在第一个位置添加元素,原来的所有元素都要向后移动
add函数,考虑到概率,时间复杂度为O(n/2),去掉常数,复杂度也为O(n)
resize函数将原来数组中的所有元素复制到新的数组中,时间复杂度为O(n)
当调用addLast函数时,如果数组已经满了,就需要resize,此时时间复杂度为O(n),这种情况下不好考虑,于是引入均摊复杂度

3.2均摊时间复杂度、复杂度震荡

如果当前数组容量为n,调用addLast函数添加元素,添加到第n+1个元素时,会调用resize
这时,addLast的时间复杂度为添加元素产生的时间复杂度和resize的复杂度之和
也就是:添加了n+1个元素,resize复制了n个元素到新的数组中,总的时间复杂度为2n+1
平均下来,addLast的时间复杂度为2,也还是O(1)

复杂度震荡
如果数组容量为n,数组存储的元素数量已经到达容量上限,调用addLast再添加一个元素会让数组容量变为2n
此时调用removeLast,数组容量又变回n
再调用addLast,变为2n,调用removeLast,变回n
如果发生了这样的情况,原本复杂度为O(1)的操作,复杂度会变得很大
因为removeLast缩容过快了(eager),将其机制修改为每当数组中的元素数量为容量的1/4时,才将容量缩小一半,
就可以解决短时间内添加元素又要调用时间复杂度为O(n)的resize的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值