【问题标题】:How does this hash function work? Are these numbers random?这个哈希函数是如何工作的?这些数字是随机的吗?
【发布时间】:2016-02-09 02:21:10
【问题描述】:

我目前正在阅读 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?

【问题讨论】:

    标签: c hash struct hashtable


    【解决方案1】:

    我不明白的是这个函数实际上是做什么的?

    它基本上对char *s指针指向的字符串进行哈希处理,直到遇到字符串的结尾,该结尾由空字符'\0'标记。换句话说,它将给定的输入字符串计算(或映射)一个整数值。

    您还可以看到,它通过遍历字符串中的每个字符(即s++)来实现这一点,使得该函数的时间复杂度线性取决于字符串长度 -- 或 @ 987654325@-- 并且通过最终的模运算避免生成超出数组边界的值。

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

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

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

    没错。这称为碰撞。编写擅长避免冲突的哈希函数并不容易。在大多数讨论中,您会看到解决冲突的方法以处理这些情况。

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

    理想情况下,会使用perfect hash functions,因为它们保证从不为两个不同的输入生成相同的哈希值,从而不需要解决冲突。

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

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

    因为 101 和 31 是 素数,因此不太可能通过将自身相乘/除以与先前的不同字符串相同的存储桶而最终产生冲突.

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2016-12-10
        • 1970-01-01
        • 2015-04-08
        • 2011-06-04
        • 2019-08-15
        • 1970-01-01
        • 2010-11-30
        • 2012-07-08
        • 1970-01-01
        相关资源
        最近更新 更多