我是否正在进行散列函数?

时间:2017-02-01 20:22:25

标签: c hash

我被指派做以下事情:

  

最简单的散列函数用于读取字符串的字符   字符并将每个字符视为无符号的8位数字   在0到255之间。然后我们添加模数为整数的所有字符   k导致0到k-1之间的整数。我们假设前一个   散列函数。散列函数添加字符串的字节   模数k。哈希表的大小为k。

因此,我编码如下:

unsigned hash (char *s)
{
 unsigned hashval;

 for (hashval = 0; *s != '\0'; s++) { 
    hashval += *s;    
}

 return hashval % HASHSIZE;
}

在这里,HASHSIZE相当于规范中的K.

但我不确定我是否做得正确,这真的是哈希函数吗?

非常感谢。

1 个答案:

答案 0 :(得分:1)

  

但我不确定我是否做得正确,这真的是哈希函数吗?

我带你去问你的代码是否准确地实现了你提供的规范。它不是,至少不是以便携方式,尽管它很接近。主要问题是它没有解决规范的这一规定:

  
    

将每个字符视为无符号8位数

  

C允许char类型签名或未签名,由实现决定。签名char非常常见,您的代码不会考虑到这一点。

此外,虽然C要求charunsigned char的大小相同,并且要求unsigned char 至少 8位,但它们都不是填充位,它不需要完全 8位。然而,在实践中,所有现代系统都使用8位char,并且练习似乎不太可能考虑到更大的系统的可能性。

要解决此问题, ,您需要将字符串中的每个char转换为无符号的8位数,然后再将其添加到累加器变量中。有几种方法可以做到这一点。如果您愿意假设unsigned char恰好有8位,那么最简单的方法就是在添加之前将每个字符强制转换为该类型。

作为次要问题,您的功能不一定实现规范中描述的模块化添加:

  
    

散列函数将字符串的字节数加为k。

  

这里的风险是字符串中所有字符的总和足以溢出类型unsigned。该类型的最大值可以小到65535(尽管在大多数现代实现中它都要大得多),并且在那个大小上,输入字符串的字符总和会溢出是合理的。在这种情况下,等到结束计算余数将产生错误的结果,除非参数 K 是2的幂。

另请注意,为结果选择类型unsigned int会将允许的 K 限制为最多UINT_MAX + 1,并使用unsigned int作为内部累加器变量与UINT_MAX - 254UINT_MAX之间 K 的值不一致(但UINT_MAX + 1仍然可以。)

要(主要)解决此问题, 在添加每个字符后计算并存储模数,而不是等到结束时才这样做。

如果您需要接近 K 接近但小于UINT_MAX + 1,那么您还需要注意添加溢出,并在事件中应用更正发生溢出。