Java 树映射或哈希映射更快

Java 树映射或哈希映射更快,java,performance,Java,Performance,我正在写一本字典,它大量使用字符串作为Map中的键。我关心的是HashMap和TreeMap中的哪一个会在地图中搜索键时产生更好(更快)的性能?HashMap是O(1)(通常)访问;树映射为O(logn)(保证) 这假设键对象是不可变的,并且具有正确编写的equals和hashCode方法。请参阅Joshua Bloch的“有效Java”,了解如何正确覆盖equals和hashCode。考虑到没有太多冲突,hashmaps将为您提供o(1)性能(对于大量冲突,这可能会降低为o(n),其中n是任何

我正在写一本字典,它大量使用字符串作为
Map
中的键。我关心的是
HashMap
TreeMap
中的哪一个会在地图中搜索键时产生更好(更快)的性能?

HashMap是O(1)(通常)访问;树映射为O(logn)(保证)


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

考虑到没有太多冲突,hashmaps将为您提供o(1)性能(对于大量冲突,这可能会降低为o(n),其中n是任何单个bucket中的条目数(冲突)。另一方面,如果您希望具有某种平衡的树结构,从而生成O(logN)检索,则可以使用树映射。因此,这实际上取决于您的特定用例。但是,如果您只想访问元素,不管它们的顺序如何,使用HashMapa
HashMap
是O(1)平均值,因此它应该更快,并且对于大型映射可能具有更好的吞吐量。
但是,当负载平衡变得过高时,
HashMap
需要重新灰化。重新刷新是O(n),因此在程序生命周期的任何时候,您都可能因重新刷新而遭受意外的性能损失,这在某些应用程序中可能是至关重要的[高延迟]。因此,如果存在问题,请在使用
HashMap
之前三思


HashMap
也容易受到较差的散列函数的影响,如果将许多正在使用的项散列到同一位置,则可能会导致O(n)。HashMap速度更快。然而,如果您经常需要按字母顺序处理词典,那么最好使用TreeMap,因为否则每次需要按字母顺序处理单词时,您都需要对所有单词进行排序


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

请检查此处-您应该首先定义“更快”您想要更好的吞吐量吗?[每秒可以处理更多项目]或更好的[更小的]延迟[每次操作获得答案的最长时间]?@amit这是一个字典,所以它必须是延迟。@amit:“更快”在这里表示映射找到键(
字符串
)并返回结果的时间。因为字符串有
hashCode
order
,所以我不知道应该使用哪一个。@Genzer:我的意思是:你喜欢一个通常工作更快,但有时出乎意料地需要更长时间的映射吗?或者是可以预测的,您确切地知道每个操作将花费多少时间,但比更快映射的平均值慢?字符串的哈希函数必须非常好。@tototo2是的,尽管有意生成的字符串在哈希桶中的分布非常差并不难。不是一个非常实用的攻击向量,但它可能是有趣的知道。是的,我知道。我正在详细说明所有案例的要求。链接已失效,请使用一个有效的链接进行修复。请在这里找到一个比查看6年前的链接更好的方法来提升您的代表性。请注意,在java8中,hashmaps将降级为O(logn)而不是O(n),您的意思是他们的最坏情况将改进为O(logn)而不是O(n)
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