为什么迭代比随机访问更优选

时间:2017-05-10 14:21:29

标签: java list

The following page

  

List接口提供了四种位置方法(索引)   访问列表元素。列表(如Java数组)基于零。注意   这些操作可以在与索引成比例的时间内执行   某些实现的值(例如LinkedList类)。   因此,迭代列表中的元素通常是优选的   如果调用者不知道实现,则通过它进行索引。

这是什么意思?这是否意味着我更喜欢

ListIterator<Integer> iterator = list.listIterator(0);
iterator.next()
iterator.next()

结束

list.get(1)

如果是这样,为什么?如果基础列表实现是普通数组,get将在恒定时间内执行。但是使用迭代器O(n)。我在这里缺少什么?

这是否意味着我应该使用list.listIterator(1);代替list.get(1)

3 个答案:

答案 0 :(得分:11)

没有。但你应该更喜欢

for (Integer value : list) {
    // do something with value
}

(或显式使用列表&#39;迭代器的循环)

for (int i = 0; i < list.size(); i++) {
    Integer value = list.get(i);
    // do something with value
}

如果列表是链表,则第一个是O(N),而第二个是O(N ^ 2)。实际上,在每次迭代时,它需要遍历列表(从开始或结束,取决于i的值),直到它到达i位置。当您使用Iterator或foreach循环时,这不会发生。

另一个好的理由是,在并发列表的情况下,迭代器可以是一致的(即迭代在创建迭代器时创建的列表的一致快照)。对于使用列表索引的迭代,情况可能不是这样。

答案 1 :(得分:3)

我几乎肯定这意味着循环遍历列表中的所有元素,最好是迭代而不是,例如:

// possibly slow depending on List implementation used
for (int i = 0; i < list.size(); ++i)
{
    Foo bar = list.get(i);
}

对于LinkedList,其中随机访问不是O(1),每次调用list.get(i)时,您都必须从一开始就一直迭代到i这是不必要的。

您的纯随机访问的示例(而不是循环遍历所有内容)是:

  1. LinkedList的情况下,更详细(但基本上是什么 get(i)引人入胜)

  2. 如果是ArrayList,实际上比get(i)

答案 2 :(得分:2)

Javadoc正在谈论的是这种情况:

for (int i = 0; i < list.size(); i++) {
    Object o = list.get(i);
}

如果list的实现是ArrayList,那么你是正确的,对每个特定元素(整个列表的O(n))访问底层数组将是恒定的时间。但是,如果它是LinkedList怎么办?要访问链接列表中的元素n,您必须在到达元素[0, 1, ... n - 2, n - 1]之前迭代n。如果对数组中的每个元素执行此操作,现在效率非常低。

因此,更好的方法是使用迭代器编写for循环:

// uses the iterator under the hood.
for (Object o : list) {

}

在这种情况下,ArrayList迭代器将沿着数组行走,因此与第一个for循环一样快,而对于LinkedList,它会跟踪列表中的位置,因此您不必遍历整个列表以获得下一个元素。