LinkedList.contains执行速度

时间:2010-05-10 16:07:19

标签: java algorithm

为什么Methode LinkedList.contains()比这样的实现运行得快:

for (String s : list) 
   if (s.equals(element))
     return true;
return false;

我认为这与实现之间没有太大区别(我认为搜索对象不是空值),同样的迭代器和等于操作

2 个答案:

答案 0 :(得分:15)

让我们看一下java.util.LinkedList的{​​{3}}(OpenJDK版本)

public boolean contains(Object o) {
    return indexOf(o) != -1;
}
public int indexOf(Object o) {
    int index = 0;
    if (o==null) {
        /* snipped */ 
    } else {
        for (Entry e = header.next; e != header; e = e.next) {
            if (o.equals(e.element))
                return index;
            index++;
        }
    }
    return -1;
}

正如您所看到的,这是一个线性搜索,就像for-each解决方案一样,所以它不是渐近更快。看看你的数字如何随着更长的列表而增长是有趣的,但它可能是一个较慢的常数因素。

原因是这个indexOf对内部结构起作用,使用直接字段访问迭代,而不是使用Iterator<E>的for-each,其方法还必须另外检查ConcurrentModificationException等等。

回到源代码,您会发现E next()的{​​{1}}返回的Iterator<E>方法如下:

LinkedList

这比private class ListItr implements ListIterator<E> { //... public E next() { checkForComodification(); if (nextIndex == size) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.element; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } 中的e = e.next;更加“繁忙”! LinkedList.contains的{​​{1}}实际上是the source code,具有更丰富的功能。你的for-each循环中不需要它们,但遗憾的是你无论如何都必须为它们付费。更不用说所有那些iterator()的防御性检查必须执行,即使你在迭代它时不会对列表进行任何修改。


结论

所以是的,使用for-each(或更直接地,使用其LinkedList)将ConcurrentModificationException作为客户端进行迭代比LinkedList本身在内部可以做的更昂贵。这是预料之中的,这就是首先提供iterator()/listIterator()的原因。

内部工作给予LinkedList巨大的优势,因为:

  • 它可以在防御性检查中偷工减料,因为它知道它没有违反任何不变量
  • 可以使用快捷方式并使用其内部表示

那你能从中学到什么? 熟悉API!查看已提供的功能;它们可能比你不得不作为客户端复制它们更快。

答案 1 :(得分:0)

我决定对此进行测试并得出一些有趣的结果

import java.util.LinkedList;

公共类包含{

private LinkedList<String> items = new LinkedList<String>();

public Contains(){
    this.addToList();
}

private void addToList(){
    for(int i=0; i<2000; i++){
        this.items.add("ItemNumber" + i);
    }
}

public boolean forEachLoop(String searchFor){
    for(String item : items){
        if(item.equals(searchFor))
            return true;
    }

    return false;
}

public boolean containsMethod(String searchFor){
    if(items.contains(searchFor))
        return true;

    return false;
}

}

和一个JUnit测试用例:



import static org.junit.Assert.assertEquals;

import org.junit.Test;



public class ContainsTest {

    @Test
    public void testForEachLoop(){
        Contains c = new Contains();

        boolean result = c.forEachLoop("ItemNumber1758");

        assertEquals("Bug!!", true, result);
    }

    @Test
    public void testContainsMethod(){
        Contains c = new Contains();

        boolean result = c.containsMethod("ItemNumber1758");

        assertEquals("Bug!!", true, result);
    }
}

这个有趣的事情是当我运行JUnit测试时,结果是:   - testForEachLoop() - 0.014s   - testContainsMethod() - 0.025s

这是真的还是我做错了什么?