Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么链接列表末尾的插入比数组列表慢_Java_Collections - Fatal编程技术网

Java 为什么链接列表末尾的插入比数组列表慢

Java 为什么链接列表末尾的插入比数组列表慢,java,collections,Java,Collections,即使链表在内部使用双链表,它也可以轻松识别最后一个元素并开始添加。现在仍然比数组列表慢为什么 请参考以下带有输出的代码: package com.collection; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class Performance { public static void main(String[] args) { List

即使链表在内部使用双链表,它也可以轻松识别最后一个元素并开始添加。现在仍然比数组列表慢为什么

请参考以下带有输出的代码:

package com.collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Performance {

    public static void main(String[] args) {
        List<Integer> arrayList = new ArrayList<Integer>();
        List<Integer> LinkedList = new LinkedList<Integer>();
        checkPerformance("arrayList", arrayList);
        checkPerformance("LinkedList", LinkedList);
    }

    private static void checkPerformance(String type, List<Integer> list) {
        for (int i = 0; i < 1E6; i++) {
        list.add(i);
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1E6; i++) {
            list.add(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("Time Taken" + " " + (end - start)
        + " ms for the type " + type);
    }
}
输出: 类型arrayList所用的时间为250毫秒
LinkedList的类型需要390毫秒的时间

事实上,对我来说完全不同,一切都如预期的那样: 类型arrayList所用的时间为184毫秒 类型LinkedList所用的时间为31毫秒

我甚至测试了这个:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TestClass   {

    public static void main(String[] args) {
        List<Integer> arrayList = new ArrayList<Integer>();
        List<Integer> LinkedList = new LinkedList<Integer>();
        checkPerformance("arrayList", arrayList);
        checkPerformance("LinkedList", LinkedList);
    }
    private static void checkPerformance(String type, List<Integer> list) {
        for (int i = 0; i < 1E4; i++) {
            list.add(i);
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1E4; i++) {
            list.get(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("Time Taken" + " " + (end - start)
                + " ms for the type " + type);
    }
}
结果是: 类型arrayList所用的时间为1毫秒 类型LinkedList所用的时间为82毫秒
果然

因此,我认为您假设ArrayList会变慢,因为它必须分配一个新数组,并在每次添加元素时将旧数组复制到新数组中,但事实并非如此

将元素添加到ArrayList时,此元素将添加到经典数组,但在此之前,它将调用以下方法以确保支持数组的大小足以添加元素:

/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
    modCount++;
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3)/2 + 1;
        if (newCapacity < minCapacity)
        newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
}
这意味着,如果备份阵列的大小不足以添加元素,它将不会像您预期的那样将大小增加到oldCapacity+1,而是增加到oldCapacity*3/2+1,以允许您向其添加更多元素,而无需再次分配和复制它

在第一个循环结束时,数组的容量将为1005308。您可以通过在循环后设置断点并检查列表变量来检查它。 因此,若要再添加1000000个元素,只需将其重新分配两次:一次从1005308分配到1507963,另一次从1507963分配到2261945。剩下的时间,您只需将备份数组中的一个元素设置为另一个值,这非常便宜


另一方面,在LinkedList中,每次向列表中添加内容时都必须分配一个新元素,并且会有更多的操作设置值,并更改两个指针值,这就是为什么它比我尝试的ArrayList花费更多时间的原因,LinkedList对我来说更快。

你应该学会如何创建合适的微基准,这是不合适的。关于你的问题:ArrayList具有更好的局部性,更改是分期付款的。运行你的代码我得到:ArrayList类型花费的时间124毫秒LinkedList类型花费的时间18毫秒。顺便说一句,这并不是对您的基准测试技术有效性的支持。而且,您的基准测试对ArrayList是不公平的:ArrayList必须重新创建一个全新的更大的数组,并在每次容量耗尽时将所有内容从旧数组复制到新数组。LinkedList只需创建一个节点并将其附加到最后一个节点。因此,在典型情况下,如果您只想测量添加元素所需的时间,请使用其最终大小:1E6初始化ArrayList。最好是您自己用纸和笔对此进行验证:对于相同的数据,在几乎所有情况下,ArrayList分配和修改的总内存都少于LinkedList。是的,即使ArrayList刚刚完成了重新分配并有一半的保留空间未使用,其累积内存使用量仍然低于LinkedList所承受的分配和链接开销。Java中LinkedList的使用案例很少,而且相差很远……因为这些都是简单的容器,您只需测量元素添加,所以内存使用与测量的时间直接相关。没有搜索正确的插入位置,没有计算散列,或者没有类似的事情,只是跟随指针并进行加法。