【问题标题】:Hashcode for strings that can be converted to integer可以转换为整数的字符串的哈希码
【发布时间】:2012-05-23 08:33:37
【问题描述】:

我正在寻找为非常特殊的字符串创建哈希码的最有效方法。

我有可以转换为整数的字符串,它们从 1 到 10,000 不等,而且非常集中在 1-600 范围内。

我的问题是,就从集合中检索项目以实现其哈希码的性能而言,最有效的方法是什么。

我的想法是:

  • 我可以将字符串转换为整数并使用直接访问表(10.000 行的数组) - 这对于检索来说非常快,但在内存分配方面不是很聪明;

  • 我可以将字符串用作字符串并为其获取哈希码(我不必将其转换为整数,但我不知道字符串的哈希码在冲突方面的效果如何)

非常感谢任何其他想法。

非常感谢

感谢大家的及时回复...

还有一个我忘记补充的信息。如果我让你知道我的最终目标,我想它会让你明白这一点——我什至可能不需要哈希表!!!

我只想针对不可变的字典验证流。我想检查给定标签是否出现在我的消息中。

我将收到一个包含多对 tag=value 的字符串。我想验证我的应用程序是否必须处理标签。

【问题讨论】:

  • 使用String的hashCode方法?这是一个很好的算法。
  • @HotLicks 但是散列码的传播呢? OP有一个合法的问题。如果情况如此受限,本机 hashCode 的性能可能是另一个问题。可能会有更多性能更好的选择。
  • @Marko,为什么你认为哈希码还没有均匀分布?
  • 就像我说的,hashCode for String 是一个非常好的算法。另一个明显的选择是使用整数值本身,但是您不能在 String 上使用简单的 HashMap —— 您必须创建自己的包装对象或混合 HashMap。
  • @HotLicks 这是一个非常好的通用算法。并在 Java 中挥洒汗水?在最后一堂课上没有高效的方法。

标签: java string int hashcode


【解决方案1】:

您可能需要考虑使用 trie (http://en.wikipedia.org/wiki/Trie) 或基数树 (http://en.wikipedia.org/wiki/Radix_tree)。无需将字符串解析为整数,或计算哈希码。当你走绳子时,你正在走一棵树。

编辑:

计算字符串的哈希码和解析字符串中的整数都涉及遍历整个字符串,然后使用该值作为对特定数据结构的查找。其他技术可能涉及在遍历数据结构的同时检查字符串。这可能对寻求“其他想法”的发帖人有价值。

【讨论】:

  • 你的回答是不符合要求的。
  • 怎么样?难道这不算是“非常感谢”的“其他想法”吗?
  • 我没有 d/v,但 OP 专门询问如何派生哈希码。
  • 虽然 OP 似乎并不真正知道他想要什么。 (这本身并不坏,但这意味着应该容忍“野鸭”的建议。)
  • 我会看看你的建议。非常感谢
【解决方案2】:

许多集合(例如 HashMap)已经应用了一种补充的“rehash”方法来帮助解决糟糕的哈希码算法。例如浏览HashMap.hash() 的源代码。并且字符串是非常常见的键,因此您可以确定 String.hashCode() 是高度优化的。所以,除非你注意到你的 hashCode 之间有很多冲突,否则我会使用标准代码。

我尝试将 0..600 的字符串放入 HashSet 以查看发生了什么,但是查看有多少条目发生冲突非常乏味。寻找你自己!如果您真的很在意,请将 HashMap 中的源代码复制到您自己的类中,对其进行编辑,以便您可以访问条目(在我正在查看的 Java 6 源代码中,这将是 transient Entry[] table,YMMV),并添加计算碰撞的方法。

【讨论】:

  • 创建一个假定哈希表大小的布尔数组,对字符串进行哈希处理,并设置相应的位。如果该位已设置,则您有冲突。您可以使用整数数组进行下一步并找到最长的链。
【解决方案3】:

如果只有有限的有效值范围,为什么不按照您的建议将集合表示为 int[10000]array[x] 处的值是x 出现的次数。

如果您的字符串表示为十进制整数,那么将它们解析为字符串是一个 5 次迭代循环(最多 5 个数字)和几个加法和减法。也就是说,它非常快。插入元素实际上是 O(1),检索是 O(1)。所需内存约为 40kb(每个 int 4 字节)。

一个问题是没有保留插入顺序。也许你不在乎。

也许您可以考虑缓存哈希码并仅在自上次调用 hashcode() 后您的集合发生更改时才更新它。见Caching hashes in Java collections?

【讨论】:

    【解决方案4】:

    «插入免责声明,仅当它是您的应用程序中的热点并且您可以证明时才这样做»

    整数值本身就是一个完美的散列函数,不会发生任何冲突。但是这种方法有两个问题:

    1. HashMap 不允许您指定自定义散列函数。因此,您要么必须实现自己的 HashMap,要么使用包装对象。
    2. HashMap 使用按位而不是模运算来查找存储桶。这显然会丢掉一些东西,因为它只是一个面具。 java.util.HashMap.hash(int) 试图弥补这一点,但我看到有人声称这不是很成功。我们再次回到实现您自己的HashMap

    既然您使用整数值作为哈希函数,为什么不使用整数值作为HashMap 中的键而不是字符串?如果你真的想优化它,你可以编写一个使用 int 而不是 Integer 键的哈希映射,或者使用 trove 中的 TIntObjectHashMap

    如果您真的对寻找好的哈希函数感兴趣,我可以推荐 Hashing in Smalltalk,请忽略作者对 Java 的咆哮(免责声明:我认识作者)。

    【讨论】:

      猜你喜欢
      • 2013-05-02
      • 2012-09-01
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-15
      • 1970-01-01
      相关资源
      最近更新 更多