【问题标题】:Data Structure / Hash Function to link Sets of Ints to Value将整数集链接到值的数据结构/哈希函数
【发布时间】:2012-10-27 17:37:01
【问题描述】:

给定 n 个整数 id,我希望将所有可能的 k 个 id 集合链接到一个常数值。我正在寻找一种将集合(例如 {1, 5}, {1, 3, 5} 和 {1, 2, 3, 4, 5, 6, 7})转换为唯一值的方法。

保证:

  • n
  • id 的顺序无关紧要:{1, 5} == {5, 1}。
  • 所有组合都是可能的,但有些可能被排除在外。
  • 所有集合和值都是不变的,并且只生成一次。没有删除或插入,没有值更新。
  • 一旦生成,唯一发生的操作就是查找。
  • 查找将是频繁且单向的(给定集合,查找值)。
  • 无需对值进行排序(或以其他方式组织)

此外,如果“相邻”集合(删除一个 id、添加一个 id、交换一个 id 等)很容易到达,以及“至少包括这个设置”。

有什么想法吗?

【问题讨论】:

  • 集合中的值是唯一的吗?使用 Zobrist 散列,或第 i 个素数的乘积。
  • 如果我正确理解了这个问题,有 nchoosek(9,99) 个唯一集,它需要大约 2^40 个唯一整数...
  • @Aki:是的,过滤将是主要障碍之一。 (9, 99) 的组合是非常不可能的情况;较高的“k”值只会出现在较低的“n”值中,反之亦然。
  • 显然我低估了...... 99 比 9 只是可能的集合之一......还有大约 1000 个,所以实际的集合数量更像是 2^50。跨度>
  • @Aki: (10, 100) 大约为 2^44。再次重申:过滤是一个主要要求,其原因不仅仅是散列。

标签: data-structures hash hashmap


【解决方案1】:

使用素数的乘积进行枚举。

  • a -> 2
  • b -> 3
  • c -> 5
  • d -> 7
  • 等等

现在哈希(ab):= 6,哈希(abc):= 30

还有一个很好的副作用是,如果“ab”是“abc”的子集,那么:

hash(abc) % hash(ab) == 0

hash(abc) / hash(ab) == hash(c)

坏消息:您可能会遇到溢出,第 100 个素数可能在 1000 左右,而 64 位无法容纳 1000**10。这不会影响作为散列函数的功能;只有子集的东西将无法工作。 the same method applied to anagrams

另一个选项是 Zobrist 散列。它等效于素数方法,但不是素数,而是使用一组固定的(随机)数字,而不是乘法,而是使用 XOR。 对于像您这样的固定小型(它需要 完美 哈希)。

最后(也是最简单的)方法是使用(100 位)位图,并将其视为哈希值(可能在模表大小之后)

完全不相关的方法是在位图的位上构建决策树。 (树的最大深度为 k)a related kD tree on bit values

【讨论】:

  • 非常优雅的解决方案。稍后我将解决更高范围的 'n' 和 'k' 的溢出问题,因为它们是一个问题,而不是单独的散列。
  • 我曾经使用 primes 来检测字谜,但我没有遇到溢出(使用 100K 组(荷兰语)单词的测试集)。我确实按频率对字母进行了排序,这样 {e,t,n} 得到较低的素数,而 {q,x,y} 得到较高的素数。顺便说一句:第 26 个素数是 101
  • 我是否正确地假设我可以通过除以 prime[X](删除 id X)、乘以 prime[X](添加 id X)以及两者的组合在相邻集的哈希之间移动?
  • 是的。除非你被溢出击中。 (我不认为模除法的工作方式相同,在高位脱落后)
【解决方案2】:

可能不是最佳解决方案,但您可以执行以下操作:

  1. 使用简单的 IntegerComparator 将集合从最低到最高排序
  2. 将集合中的每一项添加到字符串中

所以如果你有 {2,5,9,4} 第一步->{2,4,5,9};秒->“2459”

这样你会从一个唯一的集合中得到一个唯一的字符串。如果确实需要将它们映射为整数值,则可以在此之后对字符串进行哈希处理。

我能想到的第二种方法是将它们存储在 java Set 中,然后简单地将其映射到 HashMapset 作为键

【讨论】:

  • 需要填零以区分 {1, 2} 和​​ {12}。我没有使用 Java,但我会看看两者的实现,看看它是否是一个选项。
【解决方案3】:

从每组 {1, 6, 87, 89} = {1,5,81,2,0,0,...} {1,2,3,4} = { 1,1,1,1,0,0,0,0... };

然后用可变长度编码对每个数字进行二进制编码并连接位。

很难比较集合(前几个相等的位除外),但由于集合中不能有很多大的间隔,所有可能的值都可能适合 64 位。 (至少 16 位的松弛...)

【讨论】:

    猜你喜欢
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    相关资源
    最近更新 更多