数据结构--顺序存储线性表(ArrayList)

一、什么是顺序存储和链式存储

1、 顺序存储方式其实就是存储的数据的内存地址是连续的,比如数组中的数据。
2、链式存储方式存储的数据的内存地址不一定是连续的,比如通过链表存储的数据。


二、顺序存储和链式存储的优缺点分析

1、顺序存储
比如顺序存储的数组中有6个数据,当删除第三个数据后,后面的数据必然会向前面移动;同理,当插入一个数据后,后面的数据也必然向后面移动。这样增删的效率显然是不高的,但是查询和修改数据是比较方便的,因为数据的内存地址是连续的,所以直接根据索引就能拿到相应的数据。

  • 优点:查询和修改的效率高
  • 缺点:增删效率不高
    数组

2、链式存储
比如链表中的数据其数据的内存地址不一定连续,是通过指针记录前一个或者后一个节点的内存地址而串联起来的。所以当要在原有的链条上增加或删除如一个节点就比较方便,只需要断开原有的链条然后再通过链条将节点串起即可。但是查询的效率比较第,因为每次都要从首节点或则尾节点通过遍历来查询到相应的节点。

  • 优点:增删效率高
  • 缺点: 查询效率低
    输入图片说明

所以在编程过程中我们需要根据实际的情况来选择数据结构,比如增删操作比较多就可以选择LinkedList来存储数据,查询操作多就可以使用ArrayList来存储数据。


三、ArrayList的分析

1、ArrayList内部数据的存储方式
通过查看ArrayList的源码,可以看到ArrayList的内部是用一个Object[]的数组来存放数据的,所以其内部数据的存储方式是顺序存储方式,其优缺点就很清楚了。


    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     *
     * Package private to allow access from java.util.Collections.
     */
    transient Object[] elementData;

通过查看其成员变量就知道其默认的容量是10,那么问题来了,当我们存储的数据超过10个它又是如何扩容的呢?

2、ArrayList的扩容
从源码中可以看到其扩容的核心方法就是grow(int minCapacity)这个方法。

  /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    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);
    }

     private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

从这句代码 int newCapacity = oldCapacity + (oldCapacity >> 1);中可以看出ArrayList扩容是增加原来容量的一半,如果还是不够那么新容量就等于所需要的容量(newCapacity = minCapacity),但是容量最大只能为Integer.MAX_VALUE这么大。在计算完所需要的容量后,ArrayList是通过数组拷贝将原有数据拷贝到一个新数组中去来完成扩容的。在这句代码中就包含了新创建一个数组及拷贝的过程:elementData = Arrays.copyOf(elementData, newCapacity);

3、ArrayList的增删改查操作
通过查看ArrayList的源码知道,其内部也是通过Object[] 存储数据的,所以ArrayList的增删改查操作都跟操作数组是一样的。增删的操作都会影响到后面的元素位置变化,所以起效率是不高的,而查询和修改的操作则比较方便,可以直接通过索引来操作元素。


本篇文章主要分析了顺序存储和链式存的优缺点,然后对顺序存储的ArrayList做了简要的分析,了解了其内部数据是通过Object[] 来存储数据的,以及它是如何扩容等操作的。

转载于:https://my.oschina.net/devbird/blog/799674

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值