(四)频繁插入和删除时使用LinkedList

本人能力有限,入行时间短,Java开发方面的基本转载,顺便记载自己的所学,以后有不当之处,本人会及时修改,一方面方便自己查阅,另一方面望对各位尽微薄之力。

本篇讲述的是列表的“写”操作,包括插入、删除、修改操作。

(1)插入元素

列表中我们使用最多的是ArrayList,下面来看看它的插入(add方法)算法,源代码如下:

public void add(int index, E element) {
		/*
		 * 检查下标是否越界
		 */
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        //若需要扩容,则增大底层数组的长度
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //给index下标之后的元素(包括当前元素)的下标+1,空出index的位置
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //给index位置的元素赋值
        elementData[index] = element;
        //列表长度+1
        size++;
    }

ArrayList的插入算法重点在arraycopy方法,从源代码可以看出ArrayList只要是插入一个元素,其后的所有元素都会向后移动一位。虽然arraycopy是一个本地方法,效率也非常高,但频繁的插入,都会使后面所有的元素进行拷贝,效率自然就变低了,特别是头位置插入元素时。不过,在开发中确实遇到插入元素的情况,可以使用LinkedList解决效率低的问题。LinkedList是一个双向链表的,它的插入只是修改相邻元素的next和previous的引用,其插入算法(add方法)源代码如下:

public void add(int index, E element) {
		//检查index位置的元素
        checkPositionIndex(index);

        if (index == size)
        	//如果index的位置是列表的长度
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

这是一个典型的双向链表的插入算法,把自己插入到链表,没有任何的元素会有拷贝的过程,只是引用地址改变了,效率自然提高了。经过实际测试,LinkedList的插入效率比ArrayList的快50倍以上。

(2)删除元素

ArrayList提供了删除指定位置上的元素、删除指定值的元素、删除一个下标范围内的元素集等删除动作,三者的实现原理基本类似,都是找到索引位置,然后删除。我们以最常用的删除指定下标位置元素的方法(remove方法)为例来看看ArrayList删除操作的性能,源代码如下:

public E remove(int index) {
		//检查index位置的下标
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        //修改计数器+1
        modCount++;
        //记录要删除元素的值
        E oldValue = (E) elementData[index];
        //记录需要向前移动的元素数量
        int numMoved = size - index - 1;
        if (numMoved > 0)
        	//index位置后的所有元素都向前移动一位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //原列表的长度-1,并且最后一位设为null
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

通过源代码可以看出ArrayList的删除操作同样进行了数组拷贝,如果数据量过大的话,必然引起性能和效率低下的问题。

我们再来看LinkedList的删除操作,LinkedList提供了非常多的列表删除操作方法,比如删除指定位置的元素、删除头元素等,与之相关的poll方法也会执行删除操作,删除操作同样没有任何的耗时过程,全部都是引用指针的变更,效率自然就会高了。在实际测试中得知,处理大批量的删除列表操作,LinkedList的效率比ArrayList快40倍以上。

(3)修改元素

在列表的修改元素方面,由于LinkedList是顺序存取的,因此定位元素必然是一个遍历的过程,效率大打折扣,远不如ArrayList。我们来看看LinkedList的set方法源代码:

public E set(int index, E element) {
		//检查index位置的元素
        checkElementIndex(index);
        //定位节点
        Node<E> x = node(index);
        E oldVal = x.item;
        //节点的元素替换
        x.item = element;
        return oldVal;
    }
LinkedList顺序存储列表的元素定位方式会折半遍历,这是一个极耗时的操作。而ArrayList的修改操作则是数组元素的直接替换,简单高效。

在修改操作上,LinkedList要不ArrayList慢很多,特别是要进行数据量比较大的修改时,两者肯定完全不在一个数量级上。

总之,LinkedList在删除和插入列表元素方面效率高,ArrayList在修改列表元素方面效率高。

 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

两者如何选择,依赖于诸位正在开发中的系统,如果是一个实时交易系统,即使写操作再少,使用LinkedList也比ArrayList合适,因为此类系统是争分夺秒的,多个N个毫秒可能就会造成交易数据不准确;而对于一个批量系统来说,几十毫秒、几百毫秒,甚至是几千毫秒的差别意义都不大,此时使用LinkedList还是ArrayList凭个人喜好,当然,如果系统已经处于性能临界点了那就必须使用LinkedList。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值