【问题标题】:Comparison: Runtime of LinkedList addFirst() vs. ArrayList add(0, item)比较:LinkedList addFirst() 与 ArrayList add(0, item) 的运行时间
【发布时间】:2013-06-23 03:09:24
【问题描述】:

我和我的搭档正在尝试对 LinkedList 数据结构进行编程。我们已经完成了数据结构,并且它可以使用所有必需的方法正常运行。我们需要对 LinkedList 类中的 addFirst() 方法与 Java ArrayList 结构的 add(0, item) 方法的运行时进行比较测试。我们的 LinkedList 数据结构的 addFirst() 方法的预期复杂度是 O(1) 常数。这在我们的测试中成立。在 ArrayList add() 方法的计时中,我们预计复杂度为 O(N),但我们再次收到大约 O(1) 常数的复杂度。这似乎是一个奇怪的差异,因为我们使用的是 Java 的 ArrayList。我们认为我们的时序结构可能存在问题,如果有人能帮助我们确定问题,我们将不胜感激。下面列出了这两种方法的计时 Java 代码:

public class timingAnalysis {

public static void main(String[] args) {

    //timeAddFirst();
    timeAddArray();

}

public static void timeAddFirst()
{
    long startTime, midTime, endTime;
    long timesToLoop = 10000;
    int inputSize = 20000;

    MyLinkedList<Long> linkedList = new MyLinkedList<Long>();

    for (; inputSize <= 1000000; inputSize = inputSize + 20000)
    {
        // Clear the collection so we can add new random
        // values.
        linkedList.clear();

        // Let some time pass to stabilize the thread.
        startTime = System.nanoTime();

        while (System.nanoTime() - startTime < 1000000000)
        {   }

        // Start timing.
        startTime = System.nanoTime();

        for (long i = 0; i < timesToLoop; i++)
            linkedList.addFirst(i);

        midTime = System.nanoTime();

        // Run an empty loop to capture the cost of running the loop.
        for (long i = 0; i < timesToLoop; i++) 
        {} // empty block

        endTime = System.nanoTime();

        // Compute the time, subtract the cost of running the loop from 
        // the cost of running the loop and computing the removeAll method.
        // Average it over the number of runs.
        double averageTime = ((midTime - startTime) - (endTime - midTime)) / timesToLoop;

        System.out.println(inputSize + " " + averageTime);
    }

}

public static void timeAddArray()
{
    long startTime, midTime, endTime;
    long timesToLoop = 10000;
    int inputSize = 20000;

    ArrayList<Long> testList = new ArrayList<Long>();

    for (; inputSize <= 1000000; inputSize = inputSize + 20000)
    {
        // Clear the collection so we can add new random
        // values.
        testList.clear();

        // Let some time pass to stabilize the thread.
        startTime = System.nanoTime();

        while (System.nanoTime() - startTime < 1000000000)
        {   }

        // Start timing.
        startTime = System.nanoTime();

        for (long i = 0; i < timesToLoop; i++)
            testList.add(0, i);

        midTime = System.nanoTime();

        // Run an empty loop to capture the cost of running the loop.
        for (long i = 0; i < timesToLoop; i++) 
        {} // empty block

        endTime = System.nanoTime();

        // Compute the time, subtract the cost of running the loop from 
        // the cost of running the loop and computing the removeAll method.
        // Average it over the number of runs.
        double averageTime = ((midTime - startTime) - (endTime - midTime)) / timesToLoop;

        System.out.println(inputSize + " " + averageTime);
    }

}

}

【问题讨论】:

    标签: java testing arraylist big-o timing


    【解决方案1】:

    您想测试不同的inputSize,但您执行的操作是测试@​​987654322@ 次数,该次数是恒定的。所以当然,这需要同样的时间。你应该使用:

    for (long i = 0; i < inputSize; i++)
        testList.add(0, i);
    

    【讨论】:

      【解决方案2】:

      据我所知,Arraylist add 操作在 O(1) 时间内运行,因此您的实验结果是正确的。我认为arrayList add 方法的常数时间是摊销的常数时间。

      根据 java 文档: 添加 n 个元素需要 O(N) 时间,这就是添加摊销常数时间的原因。

      【讨论】:

      • 不,add(index,value) 是线性的,不是摊销常数:docs.oracle.com/javase/6/docs/api/java/util/…, E)。只有 add(value) 是摊销常数,通过在末尾添加元素。
      • @Makoto: void add(int index, E element) Inserts the specified element at the specified position in this list. Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
      • 一定是匆忙错过了这条线。感谢您的澄清。
      • @Makoto 实际上,我不得不说 Java 文档不清楚。它确实说 add (没有任何精度)是摊销常数,并且 - 可能 - 也可以在摊销常数中实现 add(int,E) (“将任何后续元素向右移动”可能是隐含的,不对它们中的每一个执行操作),特别是对于特殊情况 index=0。但不是 Java 实现 get(int) 的方式
      • @Boris :是的,实际上这就是我在阅读 java doc 时的想法,因此得到了这个答案。但是从他们对 add(index,E) 的解释看来,它必须是 O(N) 操作。我在想,如果是的话,它可能是恒定时间操作。
      猜你喜欢
      • 2013-12-23
      • 2014-12-31
      • 2012-08-17
      • 2014-12-07
      • 2016-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      相关资源
      最近更新 更多