从列表中获取/删除第一个元素的有效方法?

时间:2015-06-04 00:57:24

标签: java list arraylist collections linked-list

我想取出并删除List中的第一个元素。我可以看到,我有两个选择:

第一种方法:

ArrayList<String> servers = new ArrayList<String>();
....
String firstServerName = servers.remove(0);

第二种方法

...
<beans>
   <bean id="serviceFactory" class="com.example.MyServiceFactory" />
   <bean id="myAction" class="com.example.MyAction" scope="request">
    <aop:scoped-proxy/>
   </bean>
   <bean id="myService" class="com.example.MyService" factory-bean="serviceFactory" factory-method="getService">
    <constructor-arg type="java.lang.String" value="myServiceConfig" />
   </bean>
</beans>
...

我的列表中有很多元素。

  • 我们应该使用哪种偏好?
  • 以上两者有什么区别?它们在性能方面在技术上是一样的吗?如果我们有很多元素,这里涉及的复杂性是什么?

最有效的方法是什么。

9 个答案:

答案 0 :(得分:5)

如果比较&#34;首先删除&#34;在ArrayListLinkedList类之间,LinkedList明显胜出。

从链接列表中删除元素需花费O(1),而对阵列(数组列表)执行此操作需要花费O(n)

答案 1 :(得分:5)

确保您了解LinkedList和ArrayList之间的区别。 ArrayList使用Array实现。

LinkedList需要一段时间来删除元素。 ArrayList可能需要线性时间来删除第一个元素(以确认我需要检查实现,而不是java专家)。

另外我认为LinkedList在空间方面更有效率。因为每次删除元素时,ArrayList都不会(也不应该)重新调整数组的大小,因此它占用的空间比所需的空间大。

答案 2 :(得分:4)

实际上,LinkedList#removeFirst更有效率,因为它在双链表上运行,第一个元素的删除基本上只包括将它从列表头部取消链接并将下一个元素更新为第一个:

private E unlinkFirst(Node<E> f) {
    // assert f == first && f != null;
    final E element = f.item;
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}

ArrayList#remove正在内部数组上运行,需要通过复制子数组将所​​有后续元素向左移一个位置:

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;
}

另一方面,LinkedList#get操作需要遍历整个列表的一半以检索指定索引处的元素 - 在最坏的情况下。 ArrayList#get将直接访问指定索引处的元素,因为它在数组上运行。

我对此提高效率的经验法则是:

  • 如果您执行了大量LinkedList / add,请使用remove 检索操作(例如:get);
  • 如果您做了很多事,请使用ArrayList 检索操作与add / remove相比较。

答案 3 :(得分:3)

使用链表要快得多。

<强>链表

它只会引用节点,因此第一个节点消失。 enter image description here

<强>的ArrayList

使用数组列表,它必须将所有元素移回一个位置以保持底层数组正确。

答案 4 :(得分:3)

删除ArrayList的第一个元素是O(n)。因为链接列表是O(1),所以我将使用它。

检查ArrayList documentation

  

运行size,isEmpty,get,set,iterator和listIterator操作   在恒定的时间。添加操作以分摊的常量时间运行,   也就是说,添加n个元素需要O(n)时间。 所有其他人   操作以线性时间运行(粗略地说)。不变因素   与LinkedList实现相比较低。

这些家伙实际上得到了OpenJDK来源link

答案 5 :(得分:3)

正如其他人正确指出的那样,LinkedList比ArrayList更快,可以从非常短的列表中删除第一个元素。

但是,要在它们之间做出选择,您需要考虑完整的操作组合。例如,如果您的工作负载为每个第一个元素删除对数百个元素列表进行了数百万次索引访问,那么ArrayList总体上会更好。

答案 6 :(得分:3)

我认为你需要的是一个ArrayDequejava.util中一个被不公平忽视的课程)。其removeFirst方法在O(1)中与LinkedList一样执行,而它通常显示ArrayList的更好的空间和时间特征。它被实现为数组中的循环队列。

您应该很少使用LinkedList。在我作为Java程序员的17年里,我做了一次,回想起来后悔了。

答案 7 :(得分:2)

如果ArrayList删除第一个元素的复杂度为O(n),那么作为替代方法,您可以获得第一个元素而不是删除它只是调用 List.subList(int fromIndex, int toIndex)

final String firstServerName = servers.get(0);
servers = servers.subList(1, servers.size());

答案 8 :(得分:1)

第三条建议。

它由java.util.Queue接口公开。 LinkedList是此接口的实现。

Queue接口正在公开E poll()方法,它有效地删除了List(队列)的头部。

就性能而言,poll()方法与removeFirst()相当。实际上它是在引擎盖下使用removeFirst()方法。