Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从字符串到整数的映射-各种方法的性能_Java_Performance_Data Structures_Big O - Fatal编程技术网

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将更快,这样计算哈希的时间就不会淹没列表线性搜索


我不知道阈值大小;这是一个实验或更好的分析问题,比我现在所能想到的要多。

你的问题在所有方面都是完全正确的:

  • HashMap
    s更好(它们使用散列)
  • 对Java代码进行基准测试很难
但是在一天结束时,您将不得不对您的特定应用程序进行基准测试。我不明白为什么HashMaps在小型情况下会更慢,但基准测试将为您提供答案,如果它是或不是

还有一个选项,a是另一个map数据结构,它使用树而不是散列来访问条目。如果您正在进行基准测试,那么您也可以对其进行基准测试


关于基准测试,一个主要的问题是垃圾收集器。但是,如果你做的测试没有分配任何对象,这应该不会是一个问题。填写你的映射/列表,然后写一个循环来获取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的相对分布