【问题标题】:Hash function for two integer arrays with minimal collisions具有最小冲突的两个整数数组的哈希函数
【发布时间】:2020-08-14 15:31:00
【问题描述】:

我正在解决一个问题,我想在数据结构(例如 hashmap)中存储由两个相等长度的整数数组(例如 int a[] ={1,2,3,4} 和 int b[] ={1,2,2,6})组成的对象。但是,对于不同的对象,两个数组的长度可能会有所不同。两个数组都由给定区间(例如 0-200 之间)的整数组成。

为了使用两个数组存储对象,我想分配一个计算速度快、保留两个序列并且将导致冲突最小化的哈希键。

我第一次尝试使用Arrays.deepHashCode(int[][]),但很快就发现了冲突。其次,我尝试通过将 a[i] 和 b[i] 更改为新值来更平均地分配数组中的值,以便 a_new[i] = Math.pow(31,a[i]) % Math.pow(2,16)(实际上使用 BigInteger 以避免溢出:BigInteger.valueOf(31).modPow(BigInteger.valueOf(a[i]), BigInteger.valueOf(Math.pow(2,16)));使用 BigInteger。由于值的间隔是有限的,我可以为每个可能的值预先计算它。结果我想出了以下解决方案:

    int result = 31;
    for (int i = 0; i < a.length; i++) {
        result = result * 31 * a_new[i];
        result = result * 31 * b_new[i];
    }

当只有较小的数组时,此解决方案似乎有效,但是一旦 a[] 和 b[] 最多可以包含 10 个值,它也会导致冲突。现在我想知道,是否有更好的方法来实现我想要的更少的碰撞。

编辑:我修复了它以使用适当的 Java 代码来获得权力

【问题讨论】:

  • 那不是真正的 Java。 Java 中没有“mod”运算符,而且......不清楚^ 是什么意思。你的意思是取幂还是按位或?向我们展示您实际使用的代码。
  • @stephen C:我想它象征着“^”的力量,而不是双星号。如果是这样,则结果 int 溢出。应该使用 Long 而不是 int(eger)
  • @StephenC:我修复了代码以使用实际的 java 代码。是的,我将“power of”与 BigInteger 结合使用来处理结果的大幂的模数。
  • 你能澄清一下你认为什么类型的对象是等价的吗?

标签: java arrays hash computation-theory hash-function


【解决方案1】:

也许不是将每个a[i]b[i] 乘以31,您可以存储一个素数数组,并将数组中的当前数字乘以prime[i]

类似这样的:

int result = 31;
int[] primes = {3, 5, 7, 11, 13, 17, 19, 23, ... };
    for (int i = 0; i < a.length; i++) {
        result = result * primes[i % primes.length] * a_new[i]
        result = result * primes[i % primes.length] * b_new[i]
    }

您也可以尝试使用更大的素数来降低碰撞的可能性。

【讨论】:

  • 我真的很喜欢这个想法,并尝试在数组中使用不同的素数(例如从 31 开始)并使用数组的修改值和原始值。尽管性能比 Objects.hash 好,但不幸的是,它在一段时间后也导致了冲突。
【解决方案2】:

只是陈述显而易见的......

return Objects.hash(a_new, b_new);

【讨论】:

    【解决方案3】:

    感谢所有回复和想法。最终,我想出了一个不同的解决方案,它似乎对我有用,并且到目前为止还没有导致任何冲突。

    我决定创建两个不同的散列,而不是为两个数组创建一个散列。一个哈希基于数组中的整数集,另一个基于序列(与我的问题相同)。然后将两个哈希用作 MultiKeyMap (Apache Commons Collections 4.4 API) 中的键,我在其中存储连接到两个数组的数据。

    基于序列的哈希:

        int result = 31;
        for (int i = 0; i < a.length; i++) {
            result = result * 31 * a_new[i];
            result = result * 31 * b_new[i];
        }
    
        return result;
    

    基于集合的哈希:

    
        int resultA = 31;
        int resultB = 179;
        for (int i = 0; i < a.length; i++) {
            resultA += a_new[i];
            resultB += b_new[i];
        }
    
       return resultA *31 * resultB;
    

    【讨论】:

      猜你喜欢
      • 2011-01-31
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 2019-03-25
      • 2016-08-02
      • 2014-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多