为什么Methode LinkedList.contains()比这样的实现运行得快:
for (String s : list)
if (s.equals(element))
return true;
return false;
我认为这与实现之间没有太大区别(我认为搜索对象不是空值),同样的迭代器和等于操作
答案 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
这是真的还是我做错了什么?