TreeMap 或 HashMap 更快[重复]

Posted

技术标签:

【中文标题】TreeMap 或 HashMap 更快[重复]【英文标题】:TreeMap or HashMap faster [duplicate] 【发布时间】:2011-10-26 19:28:21 【问题描述】:

我正在编写一个字典,它大量使用字符串作为Map<String, Index> 中的键。我关心的是HashMapTreeMap 中的哪一个会在地图中搜索键时带来更好(更快)的性能?

【问题讨论】:

检查这里 - ***.com/questions/302371/… 您应该首先定义“更快”您想要更好的吞吐量吗? [每秒可以处理更多项目]还是更好[更小]延迟[每个 OP 获得答案的最长时间]? @amit 它是一本字典,所以它必须是延迟。 @amit:这里的“更快”是指地图找到密钥(String)并返回结果的时间。因为String有hashCodeorder所以我就是不知道应该用哪一个。 @Genzer:我的意思是:您是否更喜欢通常运行速度更快但有时会花费更长时间的地图?或可预测的东西,您确切知道每个操作将花费多少时间,但比更快的地图的平均值要慢? 【参考方案1】:

鉴于没有太多碰撞,哈希图将为您提供 o(1) 的性能(如果有很多碰撞,这可能会降低到 O(n),其中 N 是任何单个存储桶中的条目(碰撞)数)。另一方面,如果您想拥有某种平衡的树结构,可以产生 O(logN) 检索,则使用 TreeMaps。因此,这实际上取决于您的特定用例。但是如果你只想访问元素,不管它们的顺序如何,都使用 HashMap

【讨论】:

小记,在java8中hashmaps会降级到O(log n)而不是O(n) javarevisited.blogspot.be/2016/01/… 你的意思是他们的最坏情况改进到O(log n)而不是O(n)【参考方案2】:
public class MapsInvestigation 

public static HashMap<String, String> hashMap = new HashMap<String, String>();
public static TreeMap<String, String> treeMap = new TreeMap<String, String>();
public static ArrayList<String> list = new ArrayList<String>();

static 
    for (int i = 0; i < 10000; i++) 
        list.add(Integer.toString(i, 16));
    



public static void main(String[] args) 
    System.out.println("Warmup populate");
    for (int i = 0; i < 1000; i++) 
        populateSet(hashMap);
        populateSet(treeMap);
    
    measureTimeToPopulate(hashMap, "HashMap", 1000);
    measureTimeToPopulate(treeMap, "TreeMap", 1000);

    System.out.println("Warmup get");
    for (int i = 0; i < 1000; i++) 
        get(hashMap);
        get(treeMap);
    
    measureTimeToContains(hashMap, "HashMap", 1000);
    measureTimeToContains(treeMap, "TreeMap", 1000);



private static void get(Map<String, String> map) 
    for (String s : list) 
        map.get(s);
    



private static void populateSet(Map<String, String> map) 
    map.clear();
    for (String s : list) 
        map.put(s, s);
    




private static void measureTimeToPopulate(Map<String, String> map, String setName, int reps) 
    long start = System.currentTimeMillis();
    for (int i = 0; i < reps; i++) 
        populateSet(map);
    
    long finish = System.currentTimeMillis();
    System.out.println("Time to populate " + (reps * map.size()) + " entries in a " + setName + ": " + (finish - start));


private static void measureTimeToContains(Map<String, String> map, String setName, int reps) 
    long start = System.currentTimeMillis();
    for (int i = 0; i < reps; i++) 
        get(map);
    
    long finish = System.currentTimeMillis();
    System.out.println("Time to get() " + (reps * map.size()) + " entries in a " + setName + ": " + (finish - start));


给出这些结果:

Warmup populate
Time to populate 10000000 entries in a HashMap: 230
Time to populate 10000000 entries in a TreeMap: 1995
Warmup get
Time to get() 10000000 entries in a HashMap: 140
Time to get() 10000000 entries in a TreeMap: 1164

【讨论】:

【参考方案3】:

HashMap 是 O(1) (通常)访问; TreeMap 为 O(log n)(保证)。

这假定您的关键对象是不可变的并且具有正确编写的 equals 和 hashCode 方法。请参阅 Joshua Bloch 的“Effective Java”chapter 3,了解如何正确覆盖 equals 和 hashCode。

【讨论】:

是的,我知道。我正在详细说明所有情况的要求。 链接已失效,web.archive.org/web/20110626160836/http://www.coderfriendly.com/… 用一个有效的修复它。请在这里找到比查看 6 年旧链接更好的方法来提高您的代表。【参考方案4】:

a HashMap 平均为 O(1),因此它应该更快,并且对于大型地图可能会有更好的吞吐量。 但是,当负载平衡变得过高时,HashMap 需要重新散列。重新散列是 O(n),因此在程序生命周期的任何时候,您都可能因重新散列而遭受意外的性能损失,这在某些应用程序中可能很关键 [高延迟]。因此,如果 latency 有问题,请在使用 HashMap 之前三思而后行!

a HashMap 也容易受到不良散列函数的影响,如果将许多正在使用的项目散列到同一个地方,这可能会导致 O(n)。

【讨论】:

String的散列函数一定不错。 @toto2 是的,尽管故意生成在哈希桶中分布很差的字符串并不难。不是一个非常实用的攻击向量,但知道它可能很有趣。【参考方案5】:

HashMap 更快。但是,如果您经常需要按字母顺序处理字典,则最好使用 TreeMap,因为否则每次需要按字母顺序处理所有单词时都需要对其进行排序。

对于您的应用程序,HashMap 是更好的选择,因为我怀疑您是否经常需要按字母顺序排序的列表。

【讨论】:

以上是关于TreeMap 或 HashMap 更快[重复]的主要内容,如果未能解决你的问题,请参考以下文章

您将使用哪种数据结构:TreeMap 或 HashMap? (Java)[重复]

您将使用哪种数据结构:TreeMap 或 HashMap? (Java)[重复]

Hashmap 与 TreeMap 的 Firebase 性能 [重复]

Java中HashMap和LinkedHashMap以及TreeMap的区别

HashMap,LinkedHashMap,TreeMap的区别(转)

HashMap,LinkedHashMap,TreeMap的区别(转)