【问题标题】:Is it faster to hash a long string for comparisons or compare the two strings?散列长字符串进行比较或比较两个字符串是否更快?
【发布时间】:2015-05-28 02:05:03
【问题描述】:
【问题讨论】:
标签:
java
string
performance
hash
【解决方案1】:
假设数据适合堆(即内存),最好的办法是使用 Set(如果每个字符串都有数据,则使用 Map)。将存储从 List 更改为 Set(使用 HashSet)或维护单独的 Set,如果您也确实需要 List。
计算字符串的hashcode() 的时间与字符串的长度成正比。假设一个正确实现的hashcode() 和适当大小的集合,查找字符串的时间相对于集合中字符串的数量是恒定的(一旦计算了哈希码)。
如果您在未排序的列表上使用equals(),则您的查找时间可能与列表中的项目数成正比。如果您保持列表排序,您可以使用比较次数进行二进制搜索以查找与列表中项目数的日志成比例的字符串(并且每次比较都必须比较字符直到找到差异)。
从本质上讲,Set 有点像将字符串的哈希码放在手边,但它更进了一步,以这样一种方式存储数据,即可以非常快速地直接跳转到集合中具有该哈希码值。
请注意,一旦发现差异,两个字符串的相等比较就可以退出,但可能必须比较两个字符串中的每个字符(当它们相等时)。如果您的字符串具有相似的长前缀,则可能会损害性能。有时,您可以从数据类型内容的知识中受益(在性能方面)。例如,如果您的所有字符串都以相同的 1K 前缀开头并且仅在结尾有所不同,则您可以从覆盖 equals() 实现以从结尾到开头进行比较而受益,因此您可以更早地发现差异。
【解决方案2】:
你的问题不够具体。
首先,我假设您的意思是“我有一个 set 非常长的字符串”,因为 list 对于状态查找来说是非常低效的结构
一些想法:
- 取决于您的字符串集(即域)的属性,前缀树在内存和速度方面似乎比任何类型的哈希表都更有效。前缀树表示比较,而不是哈希计算。
- 否则,您最终应该使用某种哈希表,这意味着无论如何您都应该计算哈希码,每个字符串至少计算一次。在这种情况下,将哈希码与字符串一起存储似乎是合理的。但是为了严格的正确性,最后你可能应该按内容比较字符串,因为哈希冲突是可能的。
- 理论上,分布良好的哈希函数的最大速度是 3-4 字节/时钟周期(即哈希函数每个 CPU 周期消耗 3-4 字节)。
- 流比较的速度 - 取决于某些条件以及您的代码的编译方式,现代 CPU 上的指令允许每个周期最多比较 16 个字节。有趣的是,
Arrays.equals 方法是内在化的,但sun.misc.Unsafe 类中没有“原始”内存比较方法。