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 ArrayList。比HashMap快。明白吗?_Java_Performance_Arraylist_Hashmap - Fatal编程技术网

Java ArrayList。比HashMap快。明白吗?

Java ArrayList。比HashMap快。明白吗?,java,performance,arraylist,hashmap,Java,Performance,Arraylist,Hashmap,我曾认为,HashMaps对单个值的随机访问比ArrayLists更快。也就是说,HashMap.get(key)应该比ArrayList.get(index)快,因为ArrayList必须遍历集合的每个元素才能达到其值,而HashMap则不然。你知道,O(1)vsO(n)等等 edit:因此我对HashMaps的理解不足,因此我感到困惑。此代码的结果与预期一致。谢谢你的解释 所以我决定在百灵鸟身上测试一下。这是我的密码: import java.util.HashMap; import jav

我曾认为,
HashMap
s对单个值的随机访问比
ArrayList
s更快。也就是说,
HashMap.get(key)
应该比
ArrayList.get(index)
快,因为
ArrayList
必须遍历集合的每个元素才能达到其值,而
HashMap
则不然。你知道,
O(1)
vs
O(n)
等等

edit:因此我对
HashMap
s的理解不足,因此我感到困惑。此代码的结果与预期一致。谢谢你的解释

所以我决定在百灵鸟身上测试一下。这是我的密码:

import java.util.HashMap;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Scanner;

public class Testing
{       

    public static void main(String[] args)
    {
        ArrayList<SomeClass> alist = new ArrayList<>();
        HashMap<Short, SomeClass> hmap = new HashMap<>(4000, (float).75);
        ListIterator<SomeClass> alistiterator = alist.listIterator();
        short j = 0;
        do
        {
            alistiterator.add(new SomeClass());
            j++;
        }
        while(j < 4000);
        for (short i = 0; i < 4000; i++)
        {
             hmap.put(i, new SomeClass());
        }
        boolean done = false;
        Scanner input = new Scanner(System.in);
        String blargh = null;
        do
        {
            System.out.println("\nEnter 1 to run iteration tests.");
            System.out.println("Enter w to run warmup (recommended)");
            System.out.println("Enter x to terminate program.");
            try
            {
                blargh = input.nextLine();
            }
            catch (NoSuchElementException e)
            {
                System.out.println("Uh, what? Try again./n");
                continue;
            }
            switch (blargh)
            {
                case "1":
                    long starttime = 0;
                    long total = 0;
                    for (short i = 0; i < 1000; i++)
                    {
                        starttime = System.nanoTime();
                        iteratearraylist(alist);
                        total += System.nanoTime() - starttime;
                    }
                    total = (long)(total * .001);
                    System.out.println(total + " ns: iterating sequentially"
                                       + " through ArrayList");
                    total = 0;
                    for (short i = 0; i< 1000; i++)
                    {
                        starttime = System.nanoTime();
                        iteratearraylistbyget(alist);
                        total += System.nanoTime() - starttime;
                    }
                    total = (long)(total * .001);                   
                    System.out.println(total + " ns: iterating sequentially"
                                       + " through ArrayList via .get()");
                    total = 0;
                    for (short i = 0; i< 1000; i++)
                    {
                        starttime = System.nanoTime();
                        iteratehashmap(hmap);
                        total += System.nanoTime() - starttime;
                    }
                    total = (long)(total * .001);           
                    System.out.println(total + " ns: iterating sequentially"
                                       + " through HashMap via .next()");
                    total = 0;
                    for (short i = 0; i< 1000; i++)
                    {
                        starttime = System.nanoTime();
                        iteratehashmapbykey(hmap);
                        total += System.nanoTime() - starttime;
                    }                   
                    total = (long)(total * .001);       
                    System.out.println(total + " ns: iterating sequentially"
                                       + " through HashMap via .get()");
                    total = 0;
                    for (short i = 0; i< 1000; i++)
                    {
                        starttime = System.nanoTime();
                        getvaluebyindex(alist);
                        total += System.nanoTime() - starttime;
                    }               
                    total = (long)(total * .001);       
                    System.out.println(total + " ns: getting end value"
                                   + " from ArrayList");
                    total = 0;
                    for (short i = 0; i< 1000; i++)
                    {
                        starttime = System.nanoTime();
                        getvaluebykey(hmap);
                        total += System.nanoTime() - starttime;
                    }           
                    total = (long)(total * .001);       
                    System.out.println(total + " ns: getting end value"
                               + " from HashMap");
                    break;
                case "w":
                    for (int i = 0; i < 60000; i++)
                    {
                        iteratearraylist(alist);
                        iteratearraylistbyget(alist);
                        iteratehashmap(hmap);
                        iteratehashmapbykey(hmap);
                        getvaluebyindex(alist);
                        getvaluebykey(hmap);
                    }
                    break;
                case "x":
                    done = true;
                    break;
                default:
                    System.out.println("Invalid entry.  Please try again.");
                    break;
            }           
        }
        while (!done);
        input.close();
    }

    public static void iteratearraylist(ArrayList<SomeClass> alist)
    {
        ListIterator<SomeClass> tempiterator = alist.listIterator();
        do
        {
            tempiterator.next();
        }
        while (tempiterator.hasNext());
    }

    public static void iteratearraylistbyget(ArrayList<SomeClass> alist)
    {
        short i = 0;        
        do
        {
            alist.get(i);
            i++;
        }
        while (i < 4000);
    }

    public static void iteratehashmap(HashMap<Short, SomeClass> hmap)
    {
        Iterator<HashMap.Entry<Short, SomeClass>> hmapiterator = 
        map.entrySet().iterator();
        do
        {
            hmapiterator.next();
        }
        while (hmapiterator.hasNext());
    }   

    public static void iteratehashmapbykey(HashMap<Short, SomeClass> hmap)
    {
        short i = 0;
        do
        {
            hmap.get(i);
            i++;
        }
        while (i < 4000);
    }

    public static void getvaluebykey(HashMap<Short, SomeClass> hmap)
    {
        hmap.get(3999);
    }

    public static void getvaluebyindex(ArrayList<SomeClass> alist)
    {
        alist.get(3999);
    }
}
有趣的是,代码似乎分阶段预热。我确定的最后一个阶段是在所有方法大约120000次迭代之后。无论如何,在我的测试机上(AMD x2-220,L3+1额外核心解锁,3.6 ghz,2.1 ghz NB),真正让我吃惊的数字是最近两次报告的数字。也就是说,
.get()
数组列表的最后一个条目(
索引==3999
)和
.get()
3999
短键关联的值所用的时间

在2-3个预热周期后,测试表明
ArrayList.get()
大约需要56纳秒,而
HashMap.get()
大约需要68纳秒。那就是。不是我所期望的。我的
HashMap
是否都被冲突吞噬了?所有键项都应该自动装箱到Shorts,Shorts应该报告它们存储的short值以响应
.hashcode()
,因此所有hashcode都应该是唯一的。我想是吧

即使没有预热,
ArrayList.get()
的速度也更快。这与我在其他地方看到的情况相反,比如。当然,我也读过,使用
列表迭代器
遍历
数组列表
比在循环中使用
.get()
更快,显然,情况并非如此

ArrayList.get(index)
通常使用固定时间,因为
ArrayList
由数组支持,所以它只在bacing数组中使用该索引
ArrayList.contains(Object)
在最坏的情况下是
O(n)
中的一个长操作

ArrayList必须遍历集合的每个元素才能达到其值

事实并非如此
ArrayList
由一个数组支持,该数组允许常量时间
get
操作


另一方面,
HashMap
get
必须首先散列其参数,然后它必须遍历散列代码所对应的bucket,测试bucket中的每个元素是否与给定的键相等。这通常比仅仅索引数组要慢。

数组列表和哈希映射都有数组支持,
HashMap
必须计算密钥的哈希代码,从该密钥派生用于访问数组的索引,而使用
get
访问ArrayList中的and元素时,则需要提供索引。因此,它对ArrayList进行了3次操作和1次操作


但无论是
列表
还是
映射
都有一个数组作为支持,这是实现细节。因此,答案可能因您使用的实现而异。

HashMap的大O是
O(1+α)
。您的α来自哈希代码冲突,必须遍历一个bucket来检查是否相等

大O用于按索引从
ArrayList
中拉出项目
O(1)


当有疑问的时候。。。把它画出来…

哈希映射在检索已知索引的内容时不会更快。如果您以已知顺序存储内容,则列表将获胜

但是假设你没有把所有的东西都插入列表1-4000,而是按照完全随机的顺序。现在,要从列表中检索正确的项目,您必须逐个检查每个项目以查找正确的项目。但是要从hashmap中检索它,您只需要知道在插入它时应该给它的密钥

所以,实际上,您应该将Hashmap.get(i)与


然后您将看到hashmap的真正效率。

为什么数组列表会遍历列表?元素位于给定索引处的数组中。在写这篇文章之前,你可以阅读ArrayList的代码来检查你的假设。是的,我知道这个名字会有多混乱。它是一个实现为数组数据结构的列表。也许您正在考虑一个链表数据结构,这是不同的。我还记得第一次看到它时我也有点不高兴。此外,对于微基准测试,请使用JMH或caliper。尝试使用不同的
hashCode()
实现并比较结果。@xdhmoore我认为这是其中的一部分,尽管事实上,我在理解ArrayList如何或何时提供O(n)性能以及HashMap在同一场景中提供O(1)性能的含义时,已经表现出了很大的无知。这是一个经常被引用的事实,我理所当然地认为这是一个涉及许多无关操作的全面声明。这是我的一个谬误。
ArrayList
实现,因此无论使用哪个实现,
get
都是常数时间。@arshajii是的,但不是
List
的每个实现都添加了一个类(
SomeOtherClass
),该类返回
.hashCode()
9999的结果(作为
short
)并在将它的单个实例放入
HashMap
时使用它为它构建一个键。我将它粘贴在
ArrayList
的索引3999处。再次使用
.hashCode()
重新生成键并“查找”在我的
HashMap
中的元素,大约花费了200 ns。在
数组列表中搜索(我将其视为bein
public class SomeClass
{
    int a = 0;
    float b = 0;
    short c = 0;

    public SomeClass()
    {
        a = (int)(Math.random() * 100000) + 1;
        b = (float)(Math.random() * 100000) + 1.0f;
        c = (short)((Math.random() * 32000) + 1);
    }
}
for(Integer i : integerList)
   if(i==value)
       //found it!