为什么Knuth,CLRS哈希函数不够

时间:2017-10-19 06:29:01

标签: hash

很容易证明,给定一些具有未知分布的键,我们不能构造一个函数,它将这些键作为输入,输出均匀分布的值。

因此,我们将研究未知发行版的通用哈希函数。

Knuth建议利用非重复数字的非重复数字 - 最值得注意的是黄金比例 - 以便在表格范围内均匀分配密钥。

CLRS建议简单地将键mod设为大素数,再次,在表范围内均匀分布键,并分解重复模式。

在这两种情况下,目标似乎是均匀分配密钥。

但是,当看到像Murmur2,SeaHash等解决方案时 - 他们似乎在确保“类似蝴蝶”的效果方面投入了大量精力:给定一个键,改变任何1位都有很好的机会改变每一位在哈希。

为什么这种行为是可取的? TAOCP和CLRS中提出的解决方案有哪些缺点?

如果所需的行为是打破输入键集中的任何模式,那么这里的隐含假设是表现出任何类型模式的键组更可能在野外?这合理吗?

很抱歉,如果我不准确的话。

编辑:不需要具有加密强度。目的是尽量减少碰撞。

1 个答案:

答案 0 :(得分:1)

我对此并不是百分之百确定,但这可能是不同作者在不同背景下做出的不同假设的假象。

Knuth在TAoCP中的工作是在开发任何其他书籍或散列函数之前完成的。当时,Knuth在某种程度上开创了如何分析和思考不同算法和数据结构的道路。当时,“使用一些方案将东西分配到桶中”的想法是众所周知的,但没有人认真考虑如何最好地选择该方案。他的方法在数学上简单而优雅,并且在当代(20世纪70年代)的硬件上运行得很快。一般的主题是“如果你要根据某些功能进行分发,这里有一个非常好用的简单的用法,背后有一个很好的理论。”

Knuth的第一篇分析数据结构或算法的论文IIRC就是在哈希表上。他在假设哈希码是均匀随机的情况下进行了分析,并表明在这些假设下哈希表表现良好。

正如您所提到的,很明显,如果您选择任何固定的哈希函数,您将会退化输入案例。一群人开始考虑如何处理这个问题,许多人尝试从可用的哈希函数池中随机选择哈希函数。在20世纪70年代后期,Wegman发表了一篇题为Universal Classes of Hash Functions的论文,该论文概述了一个正式的数学定义,它定义了一系列散列函数对于一个好的哈希函数类来说是什么意思。本文包含一个证明,即通用的哈希函数族具有较低的预期冲突数,这使得它们非常适用于链式哈希表。

CLRS的第一版于1990年出版,并结合了Knuth对线性探测的分析(假设真正随机的哈希码)和使用通用哈希的链式哈希表分析。换句话说,它承认你在选择哈希函数时必须要小心(没有一个固定函数会一直工作,所以看看通用哈希),但也假设你有一个“足够好”的哈希函数做一些数学运算。

(后来的理论发展包括具有里程碑意义的论文“为什么简单的哈希函数起作用”,解释了为什么弱哈希函数与输入分布中的微量熵相结合基本上就像真正的随机函数一样,后来的一些工作显示出5-您需要独立的散列函数才能在线性探测表中获得非常好的性能。)

以上所有工作都在Theoryland,其目标是建立良好的数学框架,用于分析数据结构,并为实践中的方法提出具体建议,以获得良好的分布和效率。

然后是真实世界,从业者并不总是得到数学,而数学经常落后于从业者正在做的事情。

如果你看一下关于散列函数的大多数工作,许多散列函数假设你正在使用可以以有意义的方式轻松分解成整数单元的数据。但是真实的数据并不总是很好地分解。或者你可能有一种语言,比如C ++,Java,Python等,其中每个对象都有一个“哈希”哈希代码 与它相关联的哈希码,而不是理论家们建议的那样。可用的哈希函数。

在这样的情况下,尝试构建一个哈希函数(1)疯狂快速评估,(2)可以在同一程序或多台机器的不同运行中工作,并且(3)并非完全不合理在实践中“足够好”,人们不会抱怨。这就是你获得像MurmurHash之类的哈希函数的地方 - 他们真的很好地填补了这个需求。假设你没有反对对抗选择的输入,那么这些散列函数就可以了。

有趣的是,我们现在看到了Knuth的复苏 乘法散列函数。允许您将不同散列函数组合在一起的库(如Boost的hash_combine)使用该技术在给定多个现有散列作为输入的情况下给出确定性但散布良好的散列码。

总结:

  • 很多这些差异都是历史性的。 Knuth为如何分析哈希函数构建了理论基础,并考虑了具有单个哈希函数的情况。后来关于通用散列的工作为处理散列函数类提供了不同的视角和框架。

  • 理论与实践之间总是存在差距。对于非对抗性情况,像MurmurHash这样的非随机哈希很简单,快速且运行良好。与单个整数值相比,它们也适用于可变长度输入。