对大量Java字符串进行排序和散列

时间:2012-05-11 01:01:12

标签: java sorting hash

我有一个应用程序可以将某种对象(比如MyClass类型)的值存储到许多不同的Map<String, MyClass>地图中。

应用程序需要

  • 将不同地图中的对象引用获取到单个集合(union)
  • 对单个集合进行排序(以应用订单)
  • 计算连续集合之间的差异(用于检测更改)
  • 从每个集合的所有对象生成单个哈希值

(统一)集合中对象的顺序很重要。

要实现排序,请使用addAll()ArrayList中放置对象(地图值),并通过Collections.sort()排序。该顺序在MyClass中定义,它通过比较它封装的一些字符串字段(例如,Comparator)来实现myField接口。

排序完成后,会生成所有对象的唯一签名。对于具有相同值myField的对象,此签名必须相同,这些对象当前通过字符串连接(使用toLowerCase()StringBuilder)完成,然后散列生成的字符串,这可能是几千个字符。

有没有更有效的方式(上述任何或所有)(复制,排序,比较和散列)?

3 个答案:

答案 0 :(得分:3)

是的,还有更好的方法。只需哈希哈希:

List<String> strings;

int hash = 0;
for (String string : strings)
    hash += hash * 31 + string.hashCode();

这几乎不会使用任何内存,速度非常快,并且会产生与StringBuilder方法强度相等的哈希码。

答案 1 :(得分:3)

如果您需要一个独特的签名,那么您(至少在概念上)需要:

  • 将相关数据连接成字符串或缓冲区;
  • 使用强哈希函数来获取该数据的哈希值。

我说“概念上”,因为您可以在不实际将所有数据复制到缓冲区的情况下动态计算哈希值:这取决于您为特定应用程序执行的方便程度。

Java中标准使用的32位哈希码通常太弱而无法为您提供唯一的代码。

我建议您至少使用64位哈希函数(我的一篇文章中有一个示例implementation of a 64-bit hash function可能有帮助)。为了给出更多的唯一性保证,更强大的散列函数(如MD5)会更理想,但是产生的散列码太宽而无法存储在原语中会带来轻微的不便。 (这是你需要做出的权衡:64强哈希通常有利于保证几百万个对象中所有意图和目的的唯一性; MD5以更宽的哈希码为代价为您提供更强大的保证。)< / p>

P.S。前几天我给this answer提出了类似的问题,这也可能有所帮助。

答案 2 :(得分:1)

假设您真正想要的只是一个以独特方式描述集合的组合哈希(因此内部排序不重要)并且仅依赖于myField,我建议:

long hash = 0
for map in maps:
    for key in keys:
        if key in map:
            hash = hash + 64bithash(map[key].myfield)

其中添加都是有效的模块2 ^ 64。这将为您提供整个集合的哈希值,该哈希值可能足够大(64位),不依赖于排序(2 + 3 = 3 + 2),并且不需要在其他结构中进行排序或存储(所以会很快)。

警告这假设订单不重要。可能是你的排序使用了比myfield更重要的东西,因此有效散列取决于myfield 订购时使用的信息。在这种情况下,上述内容将不起作用(但可以通过在has中包含用于订购的信息来实现)。