我想使用LinkedList或ArrayList分析移动1 2 3 4
到3 1 2 4
(整数列表)。
我做了什么:
aux = arraylist.get(2); // O(1)
arraylist.remove(2); // O(n)
arraylist.add(0, aux); // O(n), shifting elements up.
aux = linkedlist.get(2); // O(n)
linkedlist.remove(2); // O(n)
linkedlist.addFirst(aux); // O(1)
那么,在这种情况下,我们可以说它们是相同的还是我错过了什么?
答案 0 :(得分:1)
您确实可以说这个特定操作对于LinkedList和ArrayList都需要O(n)
时间。
但你不能说他们因此而花费相同的实时时间。
Big-O表示法仅告诉您运行时间如何随着输入变大而缩放,因为它忽略了常数因子。因此,O(n)
算法最多可以执行1*n
次操作或100000*n
次操作或更多操作,并且每次操作都会花费大量不同的时间。这也意味着它通常对小输入的性能测量非常不准确,因为恒定因素对运行时间的影响大于小输入的大小(但对于小输入,性能差异往往不那么重要) )。
另请参阅:What is a plain English explanation of "Big O" notation?
答案 1 :(得分:0)
这是一个快速而肮脏的基准。我计时两次,重复一百万次:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
int arrayListTime = 0;
int linkedListTime = 0;
int n = 10000000;
for (int i=0; i<n; i++) {
ArrayList<Integer> A = new ArrayList<>(Arrays.asList(1,2,3,4));
long startTime = System.currentTimeMillis();
int x = A.remove(2);
A.add(0, x);
long endTime = System.currentTimeMillis();
arrayListTime += (endTime - startTime);
LinkedList<Integer> L = new LinkedList<>(Arrays.asList(1,2,3,4));
long startTime2 = System.currentTimeMillis();
int x2 = L.remove(2);
L.addFirst(x2);
long endTime2 = System.currentTimeMillis();
linkedListTime += (endTime2 - startTime2);
}
System.out.println(arrayListTime);
System.out.println(linkedListTime);
}
}
差异很小。我的输出是:
424
363
因此,在1,000,000次操作过程中,使用LinkedList的速度仅提高了61ms。
答案 2 :(得分:0)
当输入非常小时,大O复杂性意味着什么,就像你的情况一样。回想一下,大O的定义只适用于“足够大的n”,我怀疑你已经达到n == 4的那个威胁。
如果这是在数据大小较小的紧密循环中运行(并且每次都有不同的数据),那么唯一真正重要的是缓存性能,并且数组列表解决方案比链接更加缓存友好列表解决方案,因为链表中的每个Node
都可能需要缓存搜索。
在这种情况下,我甚至更喜欢使用原始数组(int[]
)来避免冗余的包装器对象,这会触发更多的缓存未命中。)