特定数组的哈希

时间:2018-09-06 17:55:51

标签: algorithm sorting hash

我有一个非常特殊的问题要有效解决。

几何由V体积定义,从0到V-1编号。 每个体积由不同的表面界定,编号从0到N-1)。

                            Volume | Surfaces
                            --------------------
Geometry A (V=2, N=7):      0      | [0 3 5 6 2] 
                            1      | [5 4 2 1]
                            2      | [4 0 1 3 6]

请注意,表面在一个体积中只会出现一次。 此外,一个表面最多包含2个几何体

这是问题所在:

我对相同的基础几何有两种不同的描述,我想找到几何A中的哪个体积与几何B中的哪个体积相对应。换句话说,我具有相同的N个曲面,但是V体积的定义不同。

这是一个可能与上面的几何A相对应的几何B:

                             Volume | Surfaces
                            --------------------
Geometry B (V=2, N=7):      0      | [1 5 4 2]
                            1      | [3 6 5 0 2] 
                            2      | [0 1 3 6 4]

鉴于几何A和B,我希望能够尽可能高效地将几何A的每个体积绑定到几何B中的相应体积。

A   0  1  2
B   1  0  2

解决方案草案:

按升序或降序对每个表面数组进行排序,而不是按照其表面的字典顺序对每个体积进行排序。通过这种方式可以轻松,可靠地解决该问题。

更好的解决方案:

为每个数组计算一个快速,唯一的哈希,而不是对该哈希之后的卷进行排序。哈希不应该取决于数组中曲面的顺序。

为什么我认为哈希可以是一个好的解决方案?

获取哈希(卷)=分钟([表面])

此哈希最多已发生1次碰撞,因为一个表面只能出现在2个体积中!

现在,如果我采用hash(Volume)= min([Surfaces])+ max([Sufaces])* N,我仍然最多发生1次碰撞,但是当存在大量体积时,发生的概率非常小和表面。

2 个答案:

答案 0 :(得分:2)

如上所述,您的解决方案非常适合您的需求。但是,如果您寻求完美的哈希函数,则可以使用以下方法:

  

假设p_i是第i个素数,使得p_0 = 2,p_1 = 3,p_2 = 5,p_3 = 7,p_4 = 11,p_5 = 13,p_6 = 17,p_7 = 19...。可以在数组中的x_0,x_1,...,x_k上定义哈希函数,使得h(x_0,...,x_k)= p_ {x_0} p_ {x_1} ... p_ {x_k}。同样,对于重复数,我们可以将重复数作为p_ {x_i}的幂。这意味着,例如,如果x_i重复3次,则h中p_ {x_i}的幂将为p_ {x_i} ^ 3。如果x_i的重复次数为a_i,则将有h(x_0,...,x_k)= p_ {x_0} ^ {a_0} p_ {x_1} ^ {a_1} ... p_ {x_k} ^ {a_k}。

因此,对于几何A,我们有:

                    Volume |      Surfaces     | Hash
                    ----------------------------------
  geometry A           0   | [0, 3, 5, 6, 2]   | 2 * 7 * 13 * 17 * 5 = 15470 
                       1   | [5, 4, 2, 1]      | 13 * 11 * 5 * 3 = 2145
                       2   | [4, 0, 1, 3, 6]   | 11 * 2 * 3 * 7 * 17 = 7854

以及类似的几何B方法。由于此函数为每个数组返回一个唯一值(与顺序无关),因此可以使用对应的哈希值排列曲面。如果N的值不大,则可以使用素数的预先计算的列表。

答案 1 :(得分:0)

我发现了一个很好的哈希函数,该函数几乎永远不会发生冲突:

V: [S_0 S_1 S_2 S_3...S_N-1]

u64 hash(V) = 0;
for i in {0..N-1} :
    hash(V) = hash(V) ^ (1<<(S_i & 63))
end

这提供了一个唯一的64位数字,并且所有数字都是可能的(与Omg的解决方案不同,鉴于表面列表中没有重复,因此大多数数字都无法获得)

在发生冲突的极端情况下(排序后将看到),我将以愚蠢的方式按字典顺序比较数组。