我正在阅读Robert Sedwick的C ++算法中的散列算法
字符串键的哈希函数的这种实现涉及键中每个字符的一次乘法和一次加法。如果我们要用128替换常量127,那么当使用Horner方法将对应于密钥的7位ASCII表示的数字除以表大小时,程序将简单地计算余数。如果表格大小是2的幂或2的倍数,则素数基数127可以帮助我们避免异常。
int hash(char *v, int M)
{ int h = 0, a = 127;
for (; *v != 0; v++)
h = (a*h + *v) % M;
return h;
}
理论上理想的通用散列函数是大小为M的表中两个不同键之间碰撞的概率精确为1 / M的函数。可以证明,对于程序14.1中的系数a,使用一系列不同的随机值而不是固定的任意值将模块化散列转换为通用散列函数。但是,为密钥中的每个字符生成新的随机数的成本可能过高。程序14.2演示了一个实际的折衷方案:我们通过生成一个简单的伪随机序列来改变系数。
总之,要对抽象符号表实现使用散列,第一步是扩展抽象类型接口以包括将键映射到小于M(表大小)的非负整数的散列操作。直接实施
内联int哈希(Key v,int M) {return(int)M *(v-s)/; }
在值s和t之间执行浮点键的工作;对于整数键,我们可以简单地返回v%M。如果M不是素数,则哈希函数可能返回
(int) (.616161 * (float) v) % M
或类似整数计算的结果,如
(16161 * (unsigned) v) % M.
我的问题作者如何表示素数基数127如果表格大小是2的幂或2的倍数,我们可以帮助我们避免异常吗?
作者的意思是“对于整数键,我们可以简单地返回v%M。”
作者的意思是“如果M不是素数,哈希函数可能会返回
(int)(。616161 *(float)v)%M
或类似整数计算的结果,如
(16161 *(无符号)v)%M。
作者如何提出.616161和16161?
通过简单的示例请求帮助以理解
答案 0 :(得分:0)
首先,基数必须与字大小共同构成,否则字符串的第一个字符对哈希值没有贡献;
e.g。 A = 256;字符串“AABA”,“AAABA”,“XYZAABA”都会产生相同的哈希值,因为中间变量 h 的计算模数为2 ^ 32。
当每个字符只使用7位时,它会稍微复杂一些,但原理成立。
对于整数键,0< = v < 2 ^ 32, M = table_size(M为素数), v % M 大致统一地计算 v 的完整范围,并考虑 v 中的所有位。
在取模数 M 之前将整数 v 乘以浮点数0.616161,保证加扰中的某些位< EM> v 。否则,正如在第一个示例中,M = 100,将所有值1001,101,201,3412341234101映射到同一个槽,忽略变量的高达90%的位。