Java 从字符串到整数的映射-各种方法的性能
假设我需要从Java 从字符串到整数的映射-各种方法的性能,java,performance,data-structures,big-o,Java,Performance,Data Structures,Big O,假设我需要从String映射到一个整数。整数是唯一的,从0开始形成一个连续的范围。即: Hello -> 0 World -> 1 Foo -> 2 Bar -> 3 Spam -> 4 Eggs -> 5 etc. 至少有两种简单的方法可以做到这一点。使用hashmap: HashMap<String, Integer> map = ... int integer = map.get(string); // Plus maybe n
String
映射到一个整数。整数是唯一的,从0开始形成一个连续的范围。即:
Hello -> 0
World -> 1
Foo -> 2
Bar -> 3
Spam -> 4
Eggs -> 5
etc.
至少有两种简单的方法可以做到这一点。使用hashmap:
HashMap<String, Integer> map = ...
int integer = map.get(string); // Plus maybe null check to avoid NPE in unboxing.
HashMap=。。。
int integer=map.get(字符串);//加上可能的空检查,以避免拆箱时出现NPE。
或列出:
List<String> list = ...
int integer = list.indexOf(string); // Plus maybe check for -1.
List=。。。
int integer=list.indexOf(字符串);//加上可能检查-1。
我应该使用哪种方法,为什么?可以说,相对性能取决于列表/映射的大小,因为list#indexOf()
是一种使用String#equals()
->O(n)效率的线性搜索,而HashMap#get()
使用哈希来缩小搜索范围->在映射较大时效率肯定更高,但在元素较少时效率可能更低(计算散列时一定会有一些开销,对吗?)
由于正确地对Java代码进行基准测试是出了名的困难,我想得到一些有根据的猜测。我上面的推理正确吗(列表对小的更好,映射对大的更好)?阈值大小大约是多少?各种
List
和HashMap
实现有什么区别?你是对的:一个列表将是O(n),一个HashMap将是O(1),因此对于足够大的n,HashMap将更快,这样计算哈希的时间就不会淹没列表线性搜索
我不知道阈值大小;这是一个实验或更好的分析问题,比我现在所能想到的要多。你的问题在所有方面都是完全正确的:
s更好(它们使用散列)HashMap
- 对Java代码进行基准测试很难
关于基准测试,一个主要的问题是垃圾收集器。但是,如果你做的测试没有分配任何对象,这应该不会是一个问题。填写你的映射/列表,然后写一个循环来获取N个随机元素,然后计时,这应该是合理的可复制的,因此信息丰富。第三个选项ion我最喜欢的可能是使用: 我打赌它在性能上优于
HashMap
(无冲突+计算哈希代码是O(字符串长度)
这一事实),在某些情况下也可能优于List
方法(例如,如果字符串有很长的公共前缀,因为indexOf将在equals
方法中浪费大量时间)
在列表和映射之间进行选择时,我会选择Map
(例如HashMap
)
- 可读性 地图界面只是为这个用例提供了一个更直观的界面
- 在正确的位置进行优化
我想说,如果你使用的是
,你无论如何都会针对小案例进行优化。这可能不是瓶颈所在列表
LinkedHashMap
,如果大小较小,则遍历它,如果大小较大,则获取关联的数字
第五个选项是将决策封装在一个单独的类中。在这种情况下,您甚至可以在运行时实现它,随着列表的增长而改变策略。据我所知,列表方法将是O(n),但会很快添加项,因为不会发生计算。您可以得到这个较低的O(logn)如果实现了b搜索或其他搜索算法,则哈希值为O(1),但插入速度较慢,因为每次添加元素时都需要计算哈希值
我知道在.net中,有一个叫做HybridDictionary的特殊集合,它就是这样做的。使用一个列表到一个点,然后是一个散列。我认为交叉大约是10,所以这可能是一个很好的选择
我想说您的上述陈述是正确的,尽管我不能100%确定列表对于小集合是否会更快,以及交叉点在哪里。不幸的是,您必须自己进行基准测试,因为相对性能将严重依赖于实际字符串值和相对概率您将测试不在映射中的字符串。当然,这取决于string.equals()
和string.hashCode()
的实现方式,以及所使用的HashMap
和列表
类的详细信息
对于HashMap
,查找通常涉及计算键字符串的哈希值,然后将键字符串与一个或多个条目键字符串进行比较。hashcode计算查看字符串的所有字符,因此依赖于键字符串。equals
操作通常会当equals
返回true
时,仔细检查所有字符,当它返回false
时,检查的字符要少得多。对给定的键字符串调用equals
的实际次数取决于散列键字符串的分布方式。通常,平均需要调用1到2次r是一个“命中”,可能是一个“未命中”最多3次
在列表
的情况下,查找将调用equals
,在“命中”的情况下平均调用一半的输入键字符串,在“未命中”的情况下调用所有的输入键字符串。如果您知道键t的相对分布