使用Iterator进行Java ArrayList而不是c-style循环

时间:2015-04-09 15:34:22

标签: java arraylist data-structures time-complexity

当迭代LinkedList时,get(i)是O(N)操作。然后我们使用Iterator对象遍历列表是有道理的。但是使用ArrayList,get(i)是O(1)。那么,在这种情况下我是否正确地说,当使用ArrayList时,无论我们使用c风格的循环还是Iterator对象,它都没有区别?

3 个答案:

答案 0 :(得分:2)

你是对的。你应该避免像这样的循环

for (int i = 0; i < linkedList.size(); i++) {
    ... linkedList.get(i) ...
}

代表LinkedList因为get(i)O(n)所以整个过程变为O(n^2)

对于ArrayListiterator.next()get(i) O(1)都无关紧要。

但是,即使对于Iterator,您通常也不需要明确使用LinkedList对象,因为foreach循环for (Object object : linkedList)无论如何都会在后台使用Iterator。< / p>

Iterator只需要在相对罕见的情况下明确使用(例如,过滤List或并行遍历两个LinkedList

答案 1 :(得分:0)

是的,O(n)两种情况都是ArrayList。如果您正在使用迭代器来查找元素,那么在最坏的情况下,您必须检查每个元素。在一般情况下,你必须检查一半。因此它仍然是O(n)

此外,迭代列表的for语法只是用于调用迭代器的语法糖。如果查看编译的字节码,您将看到它调用列表的迭代器。

例如,以下代码:

import java.util.*;

public class IterTest {

    public static void main() {
        List<String> l = new ArrayList<>();

        for(String s : l) {
            System.out.println(s);
        }
    }
}

具有以下字节码:

Compiled from "IterTest.java"
public class IterTest {
  public IterTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main();
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_0
       8: aload_0
       9: invokeinterface #4,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      14: astore_1
      15: aload_1
      16: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      21: ifeq          44
      24: aload_1
      25: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      30: checkcast     #7                  // class java/lang/String
      33: astore_2
      34: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      37: aload_2
      38: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      41: goto          15
      44: return

你可以看到它使用迭代器遍历列表。

<强>更新

回应你的评论:

如果使用for,带有索引的for循环将具有与显式迭代器和ArrayList迭代器样式循环相同的性能。

但是,使用带有for索引的LinkedList将严格(平均)比ArrayList更严重,因为对于每个索引,您正在执行 O(n)查找。因此,您的总体表现实际上最终是 O(n 2

答案 2 :(得分:0)

与while循环相比,使用Iterator在删除元素时更不容易出错,因为在删除时你不必调整某个位置值(i,光标,无论你怎么称呼它) 。正如@Vivin Paliath解释的那样,for循环已经在使用迭代器了,并且不能使用删除(删除会导致ConcurrentModificationException)。