这个哈希函数如何工作?这些数字是随机的吗?

时间:2015-11-08 08:42:48

标签: c hash struct hashtable

我正在阅读K& R的“The C Programming Language”一书。在“结构”一章中,在“表查找”(页144)的子主题下,我发现了这个哈希生成函数

#define HASHSIZE 101

struct nlist {
    struct nlist *next;
    char *name;
    char *defn;
}

static struct nlist *hashtab[HASHSIZE];

unsigned hash(char *s)
{
    unsigned hashval;

    for (hashval = 0; *s != '\0'; s++)
        hashval = *s + 31 * hashval;
    return hashval % HASHSIZE;
}

我不明白这个功能实际上是做什么的。

我认为它为给定的字符串(char * s)生成一个唯一的地址(作为hashtab的索引)。

但我认为两个不同的字符串可以赋予相同的索引,因为(hashval%HASHSIZE)是给定的地址(203%101 = 405%101 = 1)。

为什么HASHSIZE 101和hashval乘以31?为什么不是100或32?

2 个答案:

答案 0 :(得分:21)

  

我不明白这个功能实际上是做什么的?

它基本上散列了char *s指针所指向的字符串,直到它遇到字符串的末尾,该字符串由空字符'\0'标记。换句话说,它会将给定输入字符串(或映射)计算为整数值。

您还可以看到它通过遍历字符串中的每个字符(即s++)来完成此操作,使此函数的时间复杂度线性依赖于字符串长度 - 或O(N) - 并且它避免使用最终模数运算生成超出数组边界的值。

  

我认为它为给定的字符串(char * s)生成一个唯一的地址(作为hashtab的索引)。

它接受输入值(即字符串被散列)并使用它来找出应该放置字符串的数组中的索引。因此,技术上不会生成地址,因为该函数不会返回指针 offset 这个词在这里会更准确。

  

但我认为两个不同的字符串可以赋予相同的索引,因为(hashval%HASHSIZE)是给定的地址(203%101 = 405%101 = 1)。

真。这称为碰撞。编写善于避免冲突的散列函数并不容易。在大多数讨论中,您将看到解决冲突的方法,以便处理这些情况。

例如,一种方法可以是将每个数组元素转换为指向链表的指针,其中附加了已经冲突的元素(即,散列相同的索引值)。还有其他方法,但这是一个不同的讨论。

理想情况下,会使用perfect hash functions,因为它们可以保证永远不会为两个不同的输入生成相同的哈希值,从而无需进行冲突解决。< / p>

有关于这些主题的书籍章节,主要是在搜索方面,所以你可能想要阅读这些章节。

  

为什么HASHSIZE为101,hashval乘以31(为什么不是100或32)?

因为101和31是 prime 数字,因此不太可能最终通过将自己与前一个和不同的字符串相乘或分成同一个桶来产生冲突

答案 1 :(得分:6)

散列函数通常可能会为不同的字符串生成相同的散列值。这就是为什么需要collision resolution

关于HASHSIZE和hashval的值:我不是哈希函数的专家,但在我读过的少数几个中,使用的数字是凭经验获得的。您可以阅读answer到另一个主题,这可能对您有帮助。