如何使用整数唯一标识一组字符串

How to uniquely identify a set of strings using an integer

这里是我的问题陈述:

我可以使用什么样的算法?

我的第一个想法是将我的字符串转换为数字,然后对它们进行运算(我想到了哈希函数),但我不确定什么公式会给我可能的结果。

有什么建议吗?

散列不起作用,因为它可能产生冲突。每个有效输入位都必须映射到输出位。

对于字母,您有 90 - 65 = 25 个不同的值,因此您可以使用 5 位来表示字母。

3 位数字有 1000 个不同的值,因此您需要 10 位。

如果将这些位组合起来,就会得到从输入到 15 位数字的唯一映射。


这种方法很简单,但可能会浪费一些比特。如果输出必须尽可能短,可以映射如下:

output = (L - 'A')*1000 + N

其中L为字母值,'A'为字母A的值,N为3位数字。然后你可以用尽可能少的位来表示output的完整范围,即25*1000 - 1 = 24999。这里又是15位,所以简单的方法不会浪费space.


如果输出位少于输入位,则需要哈希函数。我强烈建议像上面那样将字符串映射到二进制数据,并使用一个简单的函数将输入映射到输出,原因如下:

通用哈希函数无法区分输入位,因为它对它们的含义一无所知。
对于 256 个输出位,在散列 5.7e38 个值之后,发生冲突的几率为 75%。资料来源:Birthday Attack

5.7e38 看起来很大,但对应的只有 129 位(2^129 = 6.8e38)。在这种情况下,这意味着有超过 75% 的机会有一对字符串 9 (129/15 = 8.6) 元素 碰撞。

另一方面,如果您使用非常简单的映射函数,例如:

  • 将输入截断为 256 位(使用每个 15 位的前 17 个元素)
  • 对所有 15 位元素求一个 256 位异或值

你可以保证最多17个元素.

的任意两个字符串之间不会发生冲突

与此处相比,为生成唯一 ID 而优化的哈希函数可能比通用哈希执行得更好,但我怀疑它们能否保证所有 256 位值的无冲突哈希。

结论:如果大多数输入字符串的元素少于 17 个,我更喜欢这个而不是散列。

您有 2^333 个可能的输入集((26 * 10^3)​​ 选择 30)。

这意味着您需要一个 333 位宽的整数来表示所有可能性。你最多只有256位,所以会有冲突。

这是哈希函数的典型应用。哈希有多种用途,因此 select 正确的类型很重要:

  • 用于基于桶的数据结构(字典)的简单散列函数必须很快。碰撞不仅是可以容忍的,而且是需要的。散列的大小(以位为单位)通常很小。由于冲突,这种类型的哈希不适合您的目的。

  • A checksum 试图避免冲突并且速度相当快。如果它足够大,这可能足以满足您的情况。

  • 加密散列 的特点是不可能(或很难)发现冲突(即使输入和散列都已知)。它们也是不可逆的(从哈希中不可能找到输入)。对于您的用例,这些通常在计算上是昂贵的并且矫枉过正。

  • 唯一标识任意输入的散列,如CityHash and SpookyHash专为快速散列和无冲突标识而设计。

SpookyHash 似乎很适合您的用例。它是 128 位宽,这意味着您需要 2^64 个不同的输入才能获得 50% 的单次碰撞机会。

它也很快:每个周期三个字节比 md5 或 sha1 快几个数量级。 SpookyHash 在 public 域中可用(参见上面的 link)。

要在您的用例上应用任何散列,您可以将列表中的项目转换为数字,但将它们作为字符串提供似乎更容易。在这种情况下,您必须接受编码(ASCII 就可以)。

当 I18N 有问题时,我通常使用 UTF8 左右。然后,有时关注规范化很重要。但这不适用于您的简单用例。