就哈希函数而言,桶是什么?

What are buckets in terms of hash functions?

看书 Mining of Massive Datasets,第 1.3.2 节概述了哈希函数。没有计算机科学背景,这对我来说很陌生; Ruby 是我的第一语言,其中 hash 似乎等同于 Dictionary<object, object>。而且我从来没有考虑过如何这种数据结构。

本书提到 散列函数,作为实现这些字典数据结构的一种方式。本段:

First, a hash function h takes a hash-key value as an argument and produces a bucket number as a result. The bucket number is an integer, normally in the range 0 to B − 1, where B is the number of buckets. Hash-keys can be of any type. There is an intuitive property of hash functions that they “randomize” hash-keys

hash function 中的桶到底是什么?听起来桶是 array-like 结构,而 hash function 是某种算法/array-like-structure 搜索,每次都会产生相同的桶号?这个比喻性的桶里面是什么?

我一直读到 javascript objects/ruby 哈希等不能保证顺序。在实践中我发现键的顺序没有改变(实际上,我认为使用旧版本的 Mozilla 的 Rhino 解释器 JS 对象顺序 DID 改变了,但我不能确定......)。

这是否意味着散列 (Ruby) / 对象 (JS) 未被这些 hash functions 解析?

hashing 这个词是否会根据您使用计算机的水平而有不同的含义?也就是说,Ruby 散列似乎与 C++ 散列不同...

当您散列一个值时,任何有用的散列函数 通常 具有比 域[=] 更小的 范围 30=]。这意味着在一个大的输入值列表(例如所有可能的字母组合)中,它将输出任何一个较小的值列表(一个以特定长度为上限的数字)。这意味着不止一个输入值可以映射到相同的输出值。

在这种情况下,输出值称为桶。

考虑函数 f(x) = x mod 2

这会生成以下输出;

1 => 1
2 => 0
3 => 1
4 => 0

在这种情况下,有两个桶(1 和 0),每个桶中都有一堆输入值。

一个好的散列函数将平等地填充所有这些 'buckets',从而实现更快的搜索等。如果你采用任何数字的 mod,你就会得到要查看的桶,并且因此必须搜索比最初搜索更少的结果,因为每个桶中的结果少于整个输入集。在理想情况下,哈希计算速度很快,每个桶中只有一个结果,这使得查找只需应用哈希函数所需的时间。

这当然是一个简化的例子,但希望你明白了吗?

散列函数的概念总是一样的。它是一个计算一些数字来表示一个对象的函数。这个号码的属性应该是:

  • 计算起来相对便宜
  • 所有对象都尽可能不同。

让我们举一个真实的例子来说明我的意思,通常使用 why/how 哈希。

取所有自然数。现在让我们假设检查 2 个数字是否相等是很昂贵的。

我们也定义一个相对便宜的散列函数如下:

hash = number % 10

思路很简单,取数字的最后一位作为hash即可。在您得到的解释中,这意味着我们将所有以 1 结尾的数字放入一个假想的 1 桶中,将所有以 2 结尾的数字放入 2 桶中,依此类推...

那些桶并不真正作为数据结构存在。它们只是让哈希函数的推理变得容易。


现在我们有了这个便宜的哈希函数,我们可以用它来降低其他事情的成本。例如,我们想创建一个新的数据结构来实现廉价的数字搜索。我们称此数据结构为哈希图。

这里其实我们把所有带hash=1的数字放在一个list/set/...里,我们把带hash=5的数字放到自己的list/set里。 ..等等

如果我们想查找一些数字,我们首先计算它的哈希值。然后我们检查这个hash对应的list/set,然后只比较"similar"个数来找到我们想要的确切数。这意味着我们只需要做一个廉价的哈希计算,然后用昂贵的相等性检查来检查 1/10 的数字。

注意这里我们使用散列函数来定义一个新的数据结构。哈希本身不是数据结构。

考虑 phone 一本书。

假设您想在 phone 书中寻找唐老鸭。

必须查看每个页面以及该页面上的每个条目,效率非常低。因此,我们没有这样做,而是做了以下事情:

  • 我们创建一个索引

  • 我们创建了一种从名称中获取索引键的方法

对于 phone 一本书,索引从 A-Z 开始,用于获取索引键的函数只是获取姓氏的第一个字母。

在这种情况下,哈希函数采用 Donald Duck 并为您提供 D。 然后你取 D 并转到所有姓氏以 D 开头的人所在的索引。

这样说太简单了。

我简单解释一下。在使用链接技术(开放式散列或封闭式寻址)处理冲突时,桶进入画面

这里,每个数组条目应对应一个桶,每个数组条目(如果非空)将有一个指向链表头部的指针。 (桶是用链表实现的)

散列table 应使用散列函数来计算存储桶数组的索引,从中可以找到所需的值。

也就是说,在检查某个元素是否在散列 table 中时,首先对键进行散列以找到要查看的正确存储桶。然后遍历对应的链表,定位到想要的元素。

类似地,在任何元素添加或删除时,散列用于找到合适的桶。然后在桶中查找presence/absence个需要的元素,据此从桶中遍历相应的链表added/removed