将元素移动到第一位时的ArrayList与LinkedList的复杂性

时间:2017-05-10 17:58:40

标签: java algorithm arraylist linked-list complexity-theory

我想使用LinkedList或ArrayList分析移动1 2 3 43 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)

那么,在这种情况下,我们可以说它们是相同的还是我错过了什么?

3 个答案:

答案 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[])来避免冗余的包装器对象,这会触发更多的缓存未命中。)