【问题标题】:Is this hash function unique?这个哈希函数是唯一的吗?
【发布时间】:2016-12-10 19:32:24
【问题描述】:

假设哈希整数永远不会溢出,以下生成的哈希对于不同的键是否总是不同的? 密钥应该包含 ascii 编码的字符。

我认为是这样,因为我想不出一个例外情况。

char[] arr = "abcd"
int hash = 0
for (int i=0; i<arr.size; i++) {
    hash += (i+1) * arr[i]
}

EDIT1:虽然以下是对我最初问题的技术正确答案,但我应该提到密钥的域是有效电子邮件 ID 的域。因此,不包括一些 ascii 字符。不过,我会进行一些测试并报告。唯一的问题是枚举所有烫发只能达到很小的长度。

无论如何,我的要求是根据电子邮件 ID 创建唯一 ID,并将它们用作数据库中的主键。只是不想自己使用邮件ID。

EDIT2: 好吧,显然有很多碰撞。例如,03N@gmail.com 的哈希 == 00P@gmail.com 的哈希

...
040 == 012
041 == 013
042 == 014
043 == 015
044 == 016
045 == 017
046 == 018
047 == 019
048 == 01:
...

我需要一个不同的散列算法。可以推荐吗?

【问题讨论】:

  • "对于不同的键,以下生成的哈希是否总是不同的?"根据“散列函数”的定义,答案是“否”。如果答案是“是”——不要称它为哈希函数。
  • 您正在占用较大的值空间并将其“压缩”到较小的空间。根据定义,至少有 2 个输入值映射到相同的输出。
  • 应该至少有一次碰撞

标签: hash unique hash-function


【解决方案1】:

否:例如 1*2 + 2*2 = 1*4 + 2*1。

char[] arr = {'\u0002','\u0002'}char[] arr = {'\u0004','\u0001'}

【讨论】:

    【解决方案2】:

    这两个字符串会生成相同的哈希值:

    "~ "
    "@?"
    

    以上内容完全由可打印的 ASCII 字符组成。

    一种蛮力测试算法的方法是简单地尝试 2 个字符的所有组合,然后可能是 3 或 4 个字符的所有组合,以了解唯一性。

    char key[5] = {0};
    bool used[65536] = {0};
    for (key[0] = " "; key[0] < 128; key[0]++)
        for (key[1] = " "; key[1] < 128; key[1]++) {
            if (used[hashcode(key)]) {
                printf("failed %s", key);
            else
                used[hashcode(key) = true;
            }
    

    【讨论】:

    • 你提到的两个值分别产生 190 和 253。
    • 哎呀,对不起@DebD。我觉得应该是
    • 很好,@DebD。我在输入之前没有仔细检查 ASCII 表是不好的,一定是读取了一个八进制值或什么的。我会尝试将第二个更正为“@?”而不是错误的“{A”
    【解决方案3】:

    在您的编辑中回答您关于寻求改进散列函数的附加问题时,您可以做的一个小改动是将每个字符乘以一个素数,然后再添加到总数中。这不能保证没有冲突,但应该减少它们,因为您添加的每个新术语将间隔更多,并且是素数的倍数。我会跳过前几个素数以获得更好的间距,所以可能将第一个字符乘以 11,第二个乘以 13,第三个乘以 17,第四个乘以 19,等等。如果你的字符串不太长,你就不需要一个很大的素数表。

    如果您真的想变得花哨,可以考虑生成 CRC,或使用线性反馈移位寄存器技术来生成签名。在后者中,您会将新字符(或新字符的选定位)异或到运行总数的最低 8 位,然后将整个总数旋转多个位。

    【讨论】:

      猜你喜欢
      • 2013-09-12
      • 2019-08-15
      • 2011-06-04
      • 2011-02-15
      • 2010-10-12
      • 2016-02-09
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      相关资源
      最近更新 更多