阅读它所说的Java documentation for the ADT List:
List接口提供了四种对列表元素进行位置(索引)访问的方法。列表(如Java数组)基于零。请注意,对于某些实现(例如,LinkedList类),这些操作可以与索引值成比例地执行。因此,如果调用者不知道实现,则迭代遍历列表中的元素通常比通过它进行索引更好。
这究竟是什么意思?我不明白得出的结论。
答案 0 :(得分:210)
在链表中,每个元素都有一个指向下一个元素的指针:
head -> item1 -> item2 -> item3 -> etc.
要访问item3
,您可以清楚地看到,您需要从头部走过每个节点,直到达到第3项,因为您无法直接跳转。
因此,如果我想打印每个元素的值,如果我写这个:
for(int i = 0; i < 4; i++) {
System.out.println(list.get(i));
}
这是怎么回事:
head -> print head
head -> item1 -> print item1
head -> item1 -> item2 -> print item2
head -> item1 -> item2 -> item3 print item3
非常低效因为每次进行索引时,它都会从列表的开头重新开始并遍历每个项目。这意味着您的复杂性只有O(N^2)
才能遍历列表!
如果我这样做了:
for(String s: list) {
System.out.println(s);
}
然后会发生什么:
head -> print head -> item1 -> print item1 -> item2 -> print item2 etc.
全部在一次遍历中,即O(N)
。
现在,转到List
的{{1}}的另一个实现,该实现由一个简单的数组支持。在这种情况下,上述两个遍历都是等价的,因为数组是连续的,所以它允许随机跳转到任意位置。
答案 1 :(得分:35)
这里隐含着答案:
请注意,对于某些实现(例如LinkedList类),这些操作可能会与索引值成比例地执行。
链表没有固有索引;调用.get(x)
将需要列表实现来查找第一个条目并调用.next()
x-1次(对于O(n)或线性时间访问),其中数组支持列表可以只索引到在O(1)或恒定时间内backingarray[x]
。
如果查看JavaDoc for LinkedList
,您会看到评论
所有操作的执行都与双向链表一样。索引到列表中的操作将从开头或结尾遍历列表,以较接近指定索引为准。
而JavaDoc for ArrayList
具有相应的
List接口的可调整大小的数组实现。实现所有可选列表操作,并允许所有元素,包括null。除了实现List接口之外,此类还提供了一些方法来操作内部用于存储列表的数组的大小。 (这个类大致相当于Vector,除了它是不同步的。)
size
,isEmpty
,get
,set
,iterator
和listIterator
操作会在固定时间内运行。添加操作以分摊的常量时间运行,即添加n个元素需要O(n)时间。所有其他操作都以线性时间运行(粗略地说)。与LinkedList
实现相比,常数因子较低。
related question titled "Big-O Summary for Java Collections Framework"有一个答案指向此资源"Java Collections JDK6",您可能会发现它有用。
答案 2 :(得分:7)
虽然接受的答案肯定是正确的,但我可以指出一个小缺陷。引用都铎王朝:
现在,转到List的另一个实现,即ArrayList, 那一个是由一个简单的数组支持。 在这种情况下都是上述两种情况 遍历是等价的,因为数组是连续的,所以它允许 随机跳到任意位置。
这不完全正确。事实是,
使用ArrayList,手写的计数循环快3倍
source: Designing for Performance, Google's Android doc
请注意,手写循环指的是索引迭代。我怀疑它是因为迭代器与增强的for循环一起使用。它在由连续数组支持的结构中产生较小的惩罚性能。我也怀疑Vector类可能是这样。
我的规则是,尽可能使用增强型for循环,如果您真的关心性能,请仅对ArrayLists或Vectors使用索引迭代。在大多数情况下,您甚至可以忽略这一点 - 编译器可能会在后台对此进行优化。
我只想指出,在Android开发环境中,ArrayLists的遍历不一定等效。只是值得深思。
答案 3 :(得分:7)
对具有查找偏移量的列表进行迭代,例如i
,类似于 Shlemiel画家的算法。
Shlemiel得到一份街头画家的作品,画出虚线 在路中间。第一天,他拿了一罐油漆 出路并完成300码的道路。 “真漂亮 好!“他的老板说,”你是一个快速工作者!“然后付给他一个科比。
第二天Shlemiel只完成150码。 “嗯,那不是 几乎与昨天一样好,但你仍然是一个快速的工人。 150码 是值得尊敬的,“并且给他一个科比。
第二天Shlemiel画了30码的路。 “只有30个!”长啸 他的老板。 “这是不可接受的!第一天你做了十次 那么多工作!发生了什么事?“
“我无法帮助它,”Shlemiel说。 “每一天我都越走越远 远离油漆罐!“
这个小故事可能会让您更容易理解内部发生的事情以及为什么效率低下。
答案 4 :(得分:4)
要查找LinkedList
的第i个元素,实现将遍历所有元素直到第i个。
所以
for(int i = 0; i < list.length ; i++ ) {
Object something = list.get(i); //Slow for LinkedList
}