展平多维HashMaps以获得更好的性能?

时间:2015-01-14 10:08:42

标签: java multidimensional-array hashmap

我经常使用多维HashMaps ,即包含HashMaps的HashMaps。例如,在双键的基础上,我用

设置/获取存储的值
hashmapMulti.get(key1).put(key2,x);
hashmapMulti.get(key1).get(key2);

但是,我也可以使用" flat" hashmap并结合使用两个键来设置/获取值:

hashmapFlat.put(key1+"|"+key2,x);
hashmapFlat.get(key1+"|"+key2);

如果我已正确通知,则put和get的时间复杂度应该"或多或少"对于HashMaps, O(1)。随着扁平化,我基本上通过组合3个字符串的成本来交换获得(恒定时间)的成本。

哪种方式更快?

最佳选择取决于HashMap中存储的对象数量吗?

4 个答案:

答案 0 :(得分:4)

第三种选择是编写一个封装复合键的类。

两个单独的键有两个字段,如果正确覆盖其equals()hashCode()方法,则不必依赖字符串连接。

虽然在性能方面你最好的选择是编写实际的基准并比较你的实现,但这绝对是最干净的解决方案:它立即可读,它避免了对字符串连接的相当脆弱的依赖(即你可以拥有密钥)包含|字符的。)

答案 1 :(得分:2)

get(key)更快。

如你所知,使用字符串(特别是连接)是性能方面的,EVIL,因为最终,连接字符串是: - 创建一个新对象String - 在第一个字符串上循环(成本:O(n)) - 在第二个字符串上循环(成本:O(n))

(在你的例子中,你做2x:1代表get,1代表put)

如果多维hashmap符合您的设计并正确表示您的建模,我认为使用它没有任何缺点。

如果你有大量的对象,二维HashMap的选择可能会给你的内存占用增加一点开销,但是因为我不知道你的costraint(对象和内存的数量)我不能如果你需要进行扁平化

答案 2 :(得分:2)

  

哪种方式更快?

您需要进行个人资料。我宁愿在默认情况下查找一个(使用biziclop's suggestion,其中我有多个键),如果存在已证实的性能问题,我只会考虑其他情况。

  

最佳选择取决于HashMap中存储的对象数量吗?

是的,但你可以管理它,以便对任意数量的对象都可以做到两个:

HashMaps有很多桶。来自密钥的哈希值,32位值被映射到更小的范围以选择桶。这意味着具有不同哈希值的对象可以共享存储桶。当对象共享存储桶时,性能会随着存储桶的线性搜索而下降。

更糟糕的情况是哈希函数返回一个常数,导致所有键映射到一个桶,最好的情况是导致桶中键值对的均匀分布。

可以增加桶的数量(HashMaps容量),结合良好的散列函数可以最大限度地减少桶的共享。

阅读本文并注意有关正确容量的建议:http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

答案 3 :(得分:1)

  

哪种方式更快?

您需要对其进行基准测试...使用与您的实际应用程序将要执行的操作密切相关的基准测试。使用真实数据运行的实际应用程序将是理想的基准。

问题是问题有太多的变量,简单的分析似乎是合理的。考虑:

  • 如果使用两层嵌套映射,则每次查找都涉及两组哈希计算,数组探测和哈希链搜索。

  • 但另一方面,使用组合键很可能需要在每次要查找时进行字符串连接。另外,如果我们假设用于查找的关键字符串是临时的,则字符串类hashcode缓存不会有效。

然后有变量:

  • 查找与其他操作的比率,
  • 条目总数
  • 组件键字符串的数量和平均长度
  • 共享/重用组件(或组合)键字符串的程度,
  • 应用程序其他部分的内存使用模式,等等。

最后,对于二阶效果的 apriori 建模存在困难,例如内存缓存,虚拟内存和应用程序上下文中的垃圾收集器的性能影响。


我的建议是使用其中一种策略实施完整的应用程序,然后对其进行基准测试(使用实际数据)并对其进行分析:

  • 如果基准测试和分析最终表明应用程序的这一部分对性能至关重要,那么使用替代策略创建应用程序的第二个版本。

  • 最后对第二个版本进行基准测试和分析,并确定哪个版本具有最佳性能。