Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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 removeAll ArrayList vs LinkedList性能_Java_Performance_Arraylist_Linked List - Fatal编程技术网

Java removeAll ArrayList vs LinkedList性能

Java removeAll ArrayList vs LinkedList性能,java,performance,arraylist,linked-list,Java,Performance,Arraylist,Linked List,我对这个节目有个问题 public class Main { public static void main(String[] args) { List<String> arrayList = new ArrayList<String>(); for(int i=0; i<100; i++){ arrayList.add("ValueA"); arrayList.add("Val

我对这个节目有个问题

public class Main {
    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<String>();
        for(int i=0; i<100; i++){
            arrayList.add("ValueA");
            arrayList.add("ValueB");
            arrayList.add(null);
            arrayList.add("ValueC");
            arrayList.add(null);
            arrayList.add(null);            
        }
        long startTime = System.nanoTime();
        arrayList.removeAll(Collections.singleton(null));
        long endTime = System.nanoTime();
        System.out.println("ArrayList removal took: " + (endTime - startTime) + "ms");          

        List<String> linkedList = new LinkedList<String>();
        for(int i=0; i<100; i++){
            linkedList.add("ValueA");
            linkedList.add("ValueB");
            linkedList.add(null);
            linkedList.add("ValueC");
            linkedList.add(null);
            linkedList.add(null);
        }

        startTime = System.nanoTime();
        linkedList.removeAll(Collections.singleton(null));
        endTime = System.nanoTime();
        System.out.println("LinkedList removal took: " + (endTime - startTime) + "ms");
    }
}
公共类主{
公共静态void main(字符串[]args){
List arrayList=新建arrayList();

对于(int i=0;i所有100个元素中的第一个元素不足以测试性能。但从理论上讲:
数组中的数据是(通常)一个接一个地存储在内存中。在链表中,你有值,还有指向另一个对象的指针。这意味着,当你删除数组时,你只需通过连接的内存块。控制如果你从链表中删除,你必须通过随机内存块,这取决于指针。数组和链表之间有更多的区别st.喜欢添加元素删除元素等。这就是为什么我们有数组和链表。看看这里

这个问题的答案归结为for循环执行时间的不同。当您深入研究这两个对象的
removeAll()
代码时,您会看到
removeAll()
ArrayList的
调用
batchRemove()
,如下所示:

private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    boolean modified = false;
    Iterator<?> it = iterator();
    while (it.hasNext()) {
        if (c.contains(it.next())) {
            it.remove();
            modified = true;
        }
    }
    return modified;
}
很明显,在
ArrayList
的情况下,与
LinkedList
中基于
迭代器的
for
循环相比,执行一个简单的
for
循环

迭代器
对于像
LinkedList
这样的数据结构更好,但是它仍然比传统的
for
数组循环要慢


您可以更多地了解这两个循环的性能差异。

正如Milkmaid提到的,这不是您应该如何进行基准测试,但我相信您得到的结果仍然有效

让我们看一下“引擎盖下”的两种实现:

ArrayList.removeAll
调用
batchRemove

private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
以下
if(r!=size)
处理从
c.contains
引发异常的情况,并使用“magic函数”
System.arraycopy
将当前索引中的其余元素复制到末尾-这部分由本机代码运行,速度应该相当快,这就是我们可以忽略它的原因

在最后一个if:
if(w!=size){…}
中,它只是将
null
s分配给列表的其余部分,以便GC能够收集符合条件的对象

操作总数为
O(n)
,每个操作都使用对阵列的直接访问

现在让我们看一看LinkedList的实现,它相当短:

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    boolean modified = false;
    Iterator<?> it = iterator();
    while (it.hasNext()) {
        if (c.contains(it.next())) {
            it.remove(); // <-- calls the iterator remove method
            modified = true;
        }
    }
    return modified;
}
这反过来又要求:

public E remove(int index) {
    rangeCheck(index);
    checkForComodification();
    E result = l.remove(index+offset); // <-- here
    this.modCount = l.modCount;
    size--;
    return result;
}
public E-remove(int-index){
范围检查(索引);
checkForComodification();

E result=l.remove(index+offset);//您能给我们提供更多的数据点吗?特别是,我想看到
ArrayList
LinkedList
的两条趋势线,为什么您希望它更快?我不认为
removeAll()
是一个特别好的基准测试,因为您只需清空整个数据结构。更好的基准测试是删除随机元素。@TimBiegeleisen,
removeAll(Collection)
并不是真的清空整个DS…他正在使用这一点…很好,我收回我所说的。在上面的代码中删除1000大小集合的第一个元素需要与
ArrayList
LinkedList
相同的时间,但是删除中间的元素需要比前者更多的时间。
public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet); // <-- this is what actually runs
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}
public E remove(int index) {
    rangeCheck(index);
    checkForComodification();
    E result = l.remove(index+offset); // <-- here
    this.modCount = l.modCount;
    size--;
    return result;
}
public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index)); // <-- here
}
E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}