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

3pmvbmvn  于 2023-02-02  发布在  Java
关注(0)|答案(9)|浏览(401)

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

    • 第一次接近:**
LinkedList<String> servers = new LinkedList<String>();
....
String firstServerName = servers.removeFirst();
    • 第二种方法**
ArrayList<String> servers = new ArrayList<String>();
....
String firstServerName = servers.remove(0);

我的清单里有很多元素。

  • 我们应该优先使用哪一个?
  • 以上两个有什么区别?从性能上来说,它们在技术上是一样的吗?如果我们有很多元素,那么复杂性是什么?

什么是最有效的方法来做到这一点。

8ehkhllq

8ehkhllq1#

如果在ArrayListLinkedList类之间比较“先删除”,LinkedList显然会胜出。
从链表中删除一个元素要花费O(1),而对数组(数组列表)执行此操作要花费O(n)

qjp7pelc

qjp7pelc2#

您应该使用LinkedList

背景:

实际上,LinkedList#removeFirst更高效,因为它是在一个双链表上操作的,并且移除第一个元素基本上只包括将其从链表的头部解除链接,并将下一个元素更新为第一个元素(复杂度O(1)):

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在内部数组结构上操作,该内部数组结构需要通过在子数组上复制来将所有后续元素向左移动一个位置(复杂度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;
}

其他答案:

另一方面,LinkedList#get操作需要遍历整个列表的一半来检索指定索引处的元素-在最坏的情况下。ArrayList#get将直接访问指定索引处的元素,因为它是在数组上操作的。
我对效率的经验法则是:

  • 如果与访问操作相比,您执行了大量add/remove操作,则使用LinkedList(例如:x 1m 10n 1x);
  • add/remove相比,如果执行了大量访问操作,则使用ArrayList
9avjhtql

9avjhtql3#

确保你理解了LinkedList和ArrayList的区别。ArrayList是用Array实现的。
LinkedList删除一个元素需要恒定的时间,ArrayList删除第一个元素可能需要线性时间(为了确认我需要检查实现,而不是这里的javaMaven)。
我还认为LinkedList在空间方面更有效,因为ArrayList不会(也不应该)在每次删除一个元素时重新调整数组的大小,所以它会占用比所需更多的空间。

7xllpg7q

7xllpg7q4#

我认为您需要的是一个ArrayDequejava.util中一个被不公平地忽略的类),它的removeFirst方法与LinkedList一样在O(1)中执行,但它通常表现出ArrayList更好的空间和时间特性,它被实现为一个数组中的循环队列。
你应该很少使用LinkedList。我在17年的Java程序员生涯中做过一次,回想起来很后悔。

sxpgvts3

sxpgvts35#

列表.子列表(从索引取整数,从索引取整数)
返回此列表中指定的fromIndex(含)和toIndex(不含)之间的部分的视图。
很适合ArrayList,其中删除第一个元素的复杂度为O(n)。

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

baubqpgj6#

移除数组列表的第一个元素是O(n),对于链表是O(1),所以我就这么做了.
检查数组列表documentation
size、isEmpty、get、set、iterator和listIterator操作在常数时间内运行。add操作在摊余常数时间内运行,即添加n个元素需要O(n)时间。所有其他操作在线性时间内运行(粗略地说)。与LinkedList实现相比,常数因子较低。
这家伙实际上得到了OpenJDK源代码link

9avjhtql

9avjhtql7#

使用链表要快得多。

链接列表

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

数组列表

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

nzk0hqpo

nzk0hqpo8#

正如其他人正确指出的那样,在从非常短的列表以外的任何列表中移除第一个元素时,LinkedList比ArrayList更快。
然而,要在它们之间做出选择,需要考虑操作的完整组合。例如,如果您的工作负载为每个第一个元素删除对一百个元素列表进行数百万次索引访问,那么ArrayList总体上会更好。

eit6fx6z

eit6fx6z9#

第三种方法

它由java.util.Queue接口公开,LinkedList是该接口的一个实现。
Queue接口公开了E poll()方法,该方法有效地删除了List(Queue)的头部。
在性能方面,poll()方法可以与removeFirst()方法相媲美,但实际上它在幕后使用了removeFirst()方法。

相关问题