hashMap.get(“String key”)的速度会受hashMap大小的影响吗?

时间:2016-01-06 12:49:43

标签: java hashmap

我提出了一个非常大胆的想法。那就是我想使用HashMap代替数据库来存储聊天应用程序的数据。

因此,当用户发送聊天消息时,该特定用户的聊天消息将使用HashMap存储到storeMsg()

每个用户都有一个独立的聊天室。每隔5秒,该特定用户的聊天室将发送getMsg()方法以检索该聊天室内的最新消息。检索邮件后,它会删除与该特定用户的聊天室相关的所有邮件,以便我们可以避免开销。

因此,只有用户存在于聊天室才能看到消息,消息可以一个一个地添加。最近进入该聊天室的新用户将无法看到之前的消息。这类似于点对点聊天。

每个用户都有一个唯一的字符串用户名,例如“tomhan12”,“Mary2”,“123cat”等。

public void storeMsg(String userName, String message){
   hMap.put(userName, message);
}

public String getMsg(String userName){
    return hMap.get(userName);
}

所以,我的问题是如果hMapKey s String s&如果hMap有数百万条记录,那么hMap.get(str)的速度会受到影响吗?

我们可以将String userName转换为唯一的整数&然后“hMap.put(thatUniqueIntegerNumber, message)”获得更高的性能?或者HashMap为我们做了这个,所以我们不需要这样做?

4 个答案:

答案 0 :(得分:7)

HashMap' get具有预期的恒定运行时间,这意味着其运行时间不应取决于HashMap的大小。当然,这取决于您的密钥的hashCode方法的正确实现,但您的密钥是String,因此它不应该是一个问题。

也就是说,使用大HashMap(或任何其他大型数据结构)会占用大量内存,所以你应该注意你没有遇到内存不足的问题,这会减慢你的速度。应用

答案 1 :(得分:2)

如果key get()函数具有良好的分布(对字符串来说是真的),则HashMap hashCode()方法提供O(1)时间复杂度。地图的大小不会影响操作性能(从技术上讲,当地图变大时,碰撞更频繁发生,但这是另一个故事)。

使用String键替换Integer键不会给您带来任何显着的性能提升。

答案 2 :(得分:1)

根据javadoc:

https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

  

此实现为基本操作(get和put)提供了恒定时间性能,假设散列函数在桶之间正确地分散元素。对集合视图的迭代需要与HashMap实例的“容量”(桶的数量)加上其大小(键 - 值映射的数量)成比例的时间。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或负载因子太低)非常重要。

     

HashMap的一个实例有两个影响其性能的参数:初始容量和负载因子。容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。当哈希表中的条目数超过加载因子和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表具有大约两倍的桶数。 / p>      

作为一般规则,默认负载系数(.75)在时间和空间成本之间提供了良好的权衡。较高的值会减少空间开销,但会增加查找成本(反映在HashMap类的大多数操作中,包括get和put)。在设置其初始容量时,应考虑映射中的预期条目数及其加载因子,以便最小化重新散列操作的数量。如果初始容量大于最大条目数除以负载因子,则不会发生任何重新连接操作。

由于HashMap将其值存储在散列桶中,因此通常可以在O(1)和O(N)之间进行查找,具体取决于映射散列的散列冲突量。

让我们测试一下这个性能:

为了测试Map的性能,我们将运行一个测试,首先将100/100000个项目插入到地图中,然后我们在循环中调用get(“0-9”)来测试性能查找。我们使用以下代码执行此操作:

import java.util.HashMap;
public class HashMapTest {
    public static void test(int items, boolean print) {
        System.gc();
        System.gc();
        HashMap<String,Object> map = new HashMap<>();
        for(int i = 0; i < items; i++) {
            map.put("" + i, map);
        }
        long start = System.nanoTime();
        for(int i = 0; i < 100000; i++) {
            map.get("0");
            map.get("1");
            map.get("2");
            map.get("3");
            map.get("4");
            map.get("5");
            map.get("6");
            map.get("7");
            map.get("8");
            map.get("9");
        }
        long end = System.nanoTime();
        long time = end - start;
        if(print) {
            System.out.println("items: "+ items + " time: "+ time);
        }
    }

    public static void main(String ... args) {
        // warmup
        for(int i = 0; i < 2; i++) {
            test(100, false);
        }
        for(int i = 0; i < 2; i++) {
            test(1000000, false);
        }
        // Real test:
        for(int i = 0; i < 10; i++) {
            test(100, true);
        }
        for(int i = 0; i < 10; i++) {
            test(1000000, true);
        }
    }
}

测试结果

items: 100     time: 11102830
items: 100     time: 12228567
items: 100     time: 34309933
items: 100     time: 36976824
items: 100     time: 34290557
items: 100     time: 19819022
items: 100     time: 14747533
items: 100     time: 15818922
items: 100     time: 15026368
items: 100     time: 16830762
items: 1000000 time: 12421862
items: 1000000 time: 13931351
items: 1000000 time: 13083504
items: 1000000 time: 11453028
items: 1000000 time: 13265455
items: 1000000 time: 11030050
items: 1000000 time: 11362288
items: 1000000 time: 11521082
items: 1000000 time: 11198296
items: 1000000 time: 11303685

items 100     min: 11102830
items 100     max: 36976824
items 1000000 min: 11030050
items 1000000 max: 13931351

如果我们分析测试结果,我们发现访问时间没有“真正的”改善,我们有1000多个项目。

答案 3 :(得分:0)

理论上HashMap#get(...)保证O(1),如果地图不是人口过多而且项目在桶之间正确分配。实际这是依赖于实现的,但如果人口过多,通常Map会慢一点。通常,HashMap的负载系数应低于0.7,以避免人口过剩并保持最佳性能。虽然减速很小(除了一些极端情况)。