我正在读这本书:Data Structures and Algorithm Analysis in Java by Mark Weiss
。有人可以解释在调用get(i)
时如何使用迭代器减少运行时间?
书中的文字摘要:
答案 0 :(得分:3)
这是因为get(i)
将从链表的头节点开始并连续移动到下一个节点,直到它返回对i
节点的引用,即O(n)
因为在将引用返回给调用者之前,它必须经过n
或更确切地说i
个不同的节点。另一方面,迭代器将存储当前节点,并且每次对next()
的连续调用将简单地使引用前进到指向当前节点之后的下一个节点,这是O(1)
操作。
get(i)
是通用的,并不假设您在列表中进行迭代,这意味着它不知道您之前查看的节点(如果有的话)。出于这个原因,它必须通过再次遍历列表的头部来重新访问i
节点。使用迭代器假设迭代,这意味着您之前查看的节点,或者说另一种方式,您将在下一个查看的节点,被假定为 next 节点,因此迭代器可以优化通过存储对当前节点的引用。这样,它不必通过链表的头部来查找下一个节点。
答案 1 :(得分:3)
Integer[] elements = new Integer[] { 4, 2, 7, 8, 1, 0, 3, 5, 9, 6 };
List<Integer> arrayList = new ArrayList<>(Arrays.asList(elements));
List<Integer> linkedList = new LinkedList<>(Arrays.asList(elements));
for (int i = 0; i < elements.length; i++) { // Runs for O(n)
Integer l1 = arrayList.get(i); // returns in O(1)
Integer l2 = linkedList.get(i); // returns in O(n)
}
对于 ArrayList 的 get(index)
直接从内存位置获取index
处的元素。
因此,get(index)
位于O(1)
get(index)
通过遍历LinkedList的head位置列表来获取index
处的元素。没有指定的内存位置可以为LinkedList的给定索引元素预测。
因此,get(index)
位于O(n)
ArrayList的总运行时间= O(1) * O(n)
= O(n)
LinkedList的总运行时间= O(n) * O(n)
= O(n^2)
使用 java.util.Iterator类
Iterator iterator = arrayList.iterator();
// total execution time: O(N)
while (iterator.hasNext()) { // runs for each element iteratively
System.out.print(iterator.next());
}
System.out.println();
iterator = linkedList.iterator();
// total execution time: O(N)
while (iterator.hasNext()) { // runs for each element iteratively
System.out.print(iterator.next());
}
System.out.println();
iterator.next()
只是迭代到List
中的下一个元素。这样做的好处是我们不需要从列表的头部搜索List Node
。 Iterator class
可帮助您将地址保留到node
的当前List
位置。
使用 for-each as iterator 可以实现相同的功能,它具有更简单的代码实现。
for (Integer I : arrayList) { // runs for each element: total execution time: O(N)
System.out.print(I); // gets in O(1)
}
System.out.println();
for (Integer I : linkedList) { // runs for each element: total execution time: O(N)
System.out.print(I); // gets in O(1)
}
因此使用迭代器,
ArrayList的总运行时间= O(n)
LinkedList = O(n)