我被指派做以下事情:
最简单的散列函数用于读取字符串的字符 字符并将每个字符视为无符号的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.
但我不确定我是否做得正确,这真的是哈希函数吗?
非常感谢。
答案 0 :(得分:1)
但我不确定我是否做得正确,这真的是哈希函数吗?
我带你去问你的代码是否准确地实现了你提供的规范。它不是,至少不是以便携方式,尽管它很接近。主要问题是它没有解决规范的这一规定:
将每个字符视为无符号8位数
C允许char
类型签名或未签名,由实现决定。签名char
非常常见,您的代码不会考虑到这一点。
此外,虽然C要求char
与unsigned 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 - 254
和UINT_MAX
之间 K 的值不一致(但UINT_MAX + 1
仍然可以。)
要(主要)解决此问题, 在添加每个字符后计算并存储模数,而不是等到结束时才这样做。
如果您需要接近 K 接近但小于UINT_MAX + 1
,那么您还需要注意添加溢出,并在事件中应用更正发生溢出。