博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【数据结构】ArrayList原理及实现学习总结(2)
阅读量:5098 次
发布时间:2019-06-13

本文共 5199 字,大约阅读时间需要 17 分钟。

ArrayList是一个基于数组实现的链表(List),这一点可以从源码中看出:

transient Object[] elementData; // non-private to simplify nested class access

可以看出ArrayList的内部是给予数组来处理的。

从ArrayList中查找一个元素的index,其时间复杂度是o(n),其源码如下所示:

public int indexOf(Object o) {        if (o == null) {            for (int i = 0; i < size; i++)                if (elementData[i]==null)                    return i;        } else {            for (int i = 0; i < size; i++)                if (o.equals(elementData[i]))                    return i;        }        return -1;    }

ArrayList支持Clone,是使用Arrays.copyOf(Object[],int)来进行的:

public Object clone() {        try {            ArrayList
v = (ArrayList
) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } }

ArrayList中根据index获取数组的时间复杂度是o(1),其源码如下:

@SuppressWarnings("unchecked")    E elementData(int index) {        return (E) elementData[index];    }    public E get(int index) {//看这里        rangeCheck(index);        return elementData(index);    }

替换指定的位置的元素,时间复杂度也是o(1):

public E set(int index, E element) {        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        return oldValue;    }

在末尾添加一个元素的时间复杂度也是o(1):

public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }

这里需要注意的是,其容量是可以扩展的,其可以扩展的最大容量是Integer.MAX_VALUE-8,由

int newCapacity = oldCapacity + (oldCapacity >> 1)

可以看出,每次是尝试扩容原来的1.5倍:

private void ensureCapacityInternal(int minCapacity) {        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }    private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            grow(minCapacity);    }    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;        int newCapacity = oldCapacity + (oldCapacity >> 1);        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        if (newCapacity - MAX_ARRAY_SIZE > 0)            newCapacity = hugeCapacity(minCapacity);        // minCapacity is usually close to size, so this is a win:        elementData = Arrays.copyOf(elementData, newCapacity);    }

添加到指定index位置的时间复杂度是o(n),这里需要先把这个位置以及之后的元素统一向后移一位:

public void add(int index, E element) {        rangeCheckForAdd(index);        ensureCapacityInternal(size + 1);  // Increments modCount!!        System.arraycopy(elementData, index, elementData, index + 1,                         size - index);        elementData[index] = element;        size++;    }

删除指定index位置的元素时间复杂度也是o(n),这里需要把这个元素之后的所有的元素向前移一位:

public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = elementData(index);        int numMoved = size - index - 1;        if (numMoved > 0)            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // clear to let GC do its work        return oldValue;    }

删除一个元素的时间复杂度也是o(n),显示查出来这个元素,删除,之后是把后面的元素向前进一位:

public boolean remove(Object o) {        if (o == null) {            for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                    return true;                }        } else {            for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                    return true;                }        }        return false;    }    private void fastRemove(int index) {        modCount++;        int numMoved = size - index - 1;        if (numMoved > 0)            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // clear to let GC do its work    }

虽然在申明存储数组的时候,申明了不可被序列化,但是只要保存的对象是可序列化的,这个ArrayList还是可以序列化的:

private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{        // Write out element count, and any hidden stuff        int expectedModCount = modCount;        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()        s.writeInt(size);        // Write out all elements in the proper order.        for (int i=0; i

 从以上的情况来看,ArrayList不是线程安全的,在进行index查找和最后插入的时候具有比较明显的时间复杂度优势。

但是,ArrayList的扩容操作,以及扩容产生的空间浪费一直是被人诟病的地方,另外在其中间进行插入的操作也不尽人意,时间复杂度是o(n)。

转载于:https://www.cnblogs.com/gxz-sw/p/8601857.html

你可能感兴趣的文章
SequenceFile介绍
查看>>
安卓 代码混淆与打包
查看>>
AT&T汇编语言及其寻址方式
查看>>
ubuntu下 java、mysql、tomcat(ssl认证) 配置
查看>>
linux命名详解及其软件安装实例
查看>>
查看iOS沙盒(SanBox)文件
查看>>
数据结构与算法
查看>>
顺时针打印矩阵
查看>>
[转载]Chrome 与 Chrome OS 各版本下载集合
查看>>
面试微软前必须要读的十本书
查看>>
JqGrid学习
查看>>
《你的灯亮着吗?发现问题的真正所在》——读书笔记
查看>>
Intel MKL(Math Kernel Library)
查看>>
51Nod 1127 最短的包含字符串 滑窗算法
查看>>
hdu4057 Rescue the Rabbit
查看>>
EhReport ,CReport改进版本,再次改进 ,V1.31
查看>>
『ORACLE』 清理监听日志(11g)
查看>>
来自于一个问题的回答对自己的反思 php怎么发送邮件?发送邮件插件PHPMailer
查看>>
找的网上的js日期格式化问题出错了显示 一堆 NaN的东西
查看>>
eclipse快捷键
查看>>