【问题标题】:hashing algorithms for strings字符串的散列算法
【发布时间】:2014-03-25 22:48:19
【问题描述】:

我正在阅读 Robert Sedwick 的 C++ 算法散列

此字符串键的哈希函数实现涉及键中每个字符的一次乘法和一次加法。如果我们将常数 127 替换为 128,则程序将使用 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 的非负整数。直接实现

inline int hash(Key v, int M) { return (int) M*(v-s)/; }

为值 s 和 t 之间的浮点键做这项工作;对于整数键,我们可以简单地返回 v % M。如果 M 不是素数,哈希函数可能会返回

(int) (.616161 * (float) v) % M

或类似整数计算的结果,例如

(16161 * (unsigned) v) % M.

如果表大小是 2 的幂或 2 的倍数,我的问题是作者如何表示素数基数 127 有助于我们避免异常?

  1. authorm 所说的“对于整数键,我们可以简单地返回 v % M”是什么意思?

  2. 作者所说的“如果 M 不是素数,哈希函数可能会返回”是什么意思

(int) (.616161 * (float) v) % M

或类似整数计算的结果,例如

(16161 * (无符号) v) % M.

作者是如何想到 .616161 和 16161 的?

请求帮助以通过简单示例理解

【问题讨论】:

    标签: c hash


    【解决方案1】:

    首先,基数必须与单词大小互质,否则字符串的第一个字符对哈希值没有贡献;

    例如a=256;字符串“AABA”、“AAABA”、“XYZAABA”都将产生相同的哈希值,因为中间变量 h 是以 2^32 为模计算的。

    每个字符仅使用 7 位时稍微复杂一些,但原则成立。

    • 对于整数键,0v M = table_size (M 是素数), v % M 大致均匀地映射了 v 的完整范围,同时考虑了 v 中的所有位。

    • 在取模 M 之前,将整数 v 乘以浮点数 0.616161,可以保证 中的位发生某种加扰 em>v。否则,就像在第一个示例中一样,当 M=100 时,会将所有值 1001、101、201、3412341234101 映射到同一个槽,忽略多达 90% 的变量位。

    【讨论】:

    • @AkiSuihkoen:感谢您的澄清。例如在上面显示的 =156 中选择的 M 的值是多少/
    • @AkiSuihoen:对不起,上面的 a =256 以及我们如何得出结论,例如,所有这些都产生相同的哈希值
    • 我们得出的结论是,Sum(str[i] * 256^i) 将 ascii 字符串转换为以 256 为基数的大量数字。当这个数字以 256^4 为模计算时,一些数字对最终值没有任何贡献。
    猜你喜欢
    • 2015-05-02
    • 1970-01-01
    • 2013-08-30
    • 2011-09-30
    • 2020-03-17
    • 2021-09-29
    • 2011-12-25
    • 2015-03-16
    • 1970-01-01
    相关资源
    最近更新 更多