Java LinkedList.com包含执行速度

Java LinkedList.com包含执行速度,java,algorithm,Java,Algorithm,为什么Methode LinkedList.contains()的运行速度比这种实现快: for (String s : list) if (s.equals(element)) return true; return false; 我不认为这与实现有很大的区别(我认为搜索对象不是空的),同样的迭代器,等于操作让我们看看(代码的)OpenGDK版本。java。UTIL.LIKEDLISTAB//COD>< /P> public boolean contains(Object

为什么Methode LinkedList.contains()的运行速度比这种实现快:

for (String s : list) 
   if (s.equals(element))
     return true;
return false;
<>我不认为这与实现有很大的区别(我认为搜索对象不是空的),同样的迭代器,等于操作

让我们看看(代码的)OpenGDK版本。java。UTIL.LIKEDLISTAB//COD>< /P>
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;
}
正如你所看到的,这是一个线性搜索,就像对每个解的搜索一样,所以它不是渐进的更快。看看你的数字是如何随着更长的列表而增长的是很有趣的,但这很可能是一个不变的因素

这样做的原因是,
indexOf
在内部结构上工作,使用直接字段访问进行迭代,而for-each使用
迭代器
,迭代器的方法还必须额外检查
ConcurrentModificationException
等内容

回到源代码,您会发现
LinkedList的
迭代器
返回的
E next()
方法如下:

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();
  }
私有类ListItr实现ListIterator{
//...
公共教育{
checkForComodification();
如果(nextIndex==大小)
抛出新的NoTouchElementException();
lastReturned=next;
next=next.next;
nextIndex++;
return lastReturned.element;
}
最终作废检查共修改(){
if(modCount!=预期的modCount)
抛出新的ConcurrentModificationException();
}
这比
LinkedList中的
e=e.next;
要忙得多。包含
!迭代器()
LinkedList的
实际上是一个,它具有更丰富的功能。在for-each循环中不需要它们,但不幸的是,无论如何你都必须为它们付费。更不用说对
ConcurrentModificationException的所有防御性检查
都必须执行,即使在此期间不会对列表进行任何修改您正在迭代它


结论 因此,是的,使用for-each(或者更直接地说,使用其
迭代器()/listIterator()
)作为客户端迭代
LinkedList
)比
LinkedList
本身内部所能做的成本更高。这是意料之中的,这就是为什么首先提供
contains

内部工作为LinkedList提供了巨大的优势,因为:

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

因此,您可以从中学到什么呢?熟悉API!看看已经提供了哪些功能;它们可能比作为客户机复制它们更快。

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

导入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测试时,结果是: -testForEachLoop()-0.014s -testContainsMethod()-0.025s


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

您测试过它并发现它运行得更快吗?还是您在假设?LinkedList.contains()的优点是,其他程序员不需要了解您的意图。


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);
    }
}