我认为您的困惑在于不知道哈希 是什么。大多数语言都有类似于键值存储的东西,在 Ruby 和 Perl 中,它们被称为 Hashes,在 Java Maps 中,在 Python 字典中等等......
它们本质上都是一样的,你将一个带有唯一键的值插入到一些底层数据结构中,以获取对它的直接访问,但会以内存为代价。
那么当你将一个键和一个值添加到哈希中时,实际会发生什么?
哈希是围绕 hash functions 的思想构建的,它采用一些值作为输入计算唯一的输出(理想情况下,每个输入都有自己的唯一输出)。如果两个输入都映射到同一个输出,这称为冲突。
现在我们需要讨论 Hash 是如何实现的,两个经典示例是使用单个数组或链表数组。我将在下面展示数组示例。
数组
在简单数组的情况下,哈希底层的数据结构只是一个一定大小的数组。散列函数用于计算该数组的索引。如果我们假设一个简单的哈希算法
h(x) = length(x) % ARRAY_SIZE
这里x是一个字符串,ARRAY_SIZE是我们底层数组的大小,这个语句将确保所有值x都在0..ARRAY_SIZE - 1范围内
看一个视觉示例,考虑一个大小为 5 的数组:
0 1 2 3 4
------------------------------
| | | | | |
------------------------------
并假设我们正在尝试根据我们的散列算法使用密钥 abcd 存储值 5
h('abcd') = length('abcd') % ARRAY_SIZE
= 4 % 5
= 4
所以5 的值将存储在索引4:
0 1 2 3 4
------------------------------
| | | | | 5 |
------------------------------
现在如果我们尝试使用键 dcba 存储值 3 会发生什么,这两个键是不同的,对吧?他们应该映射到不同的地方。
h('dcba') = length('dcba') % ARRAY_SIZE
= 4 % 5
= 4
哎呀!这个键也映射到索引4 那么我们现在要做什么呢?好吧,我们不能仅仅丢弃键值对,因为程序员显然需要/希望在他们的 Hash 中使用这种配对,所以我们需要决定在发生冲突时该怎么做。有很多算法可以做到这一点,但最简单的一种是在数组中寻找下一个开放的槽并存储3它们。所以现在我们的数组看起来像:
0 1 2 3 4
------------------------------
| 3 | | | | 5 |
------------------------------
这不是一个非常深入的解释,但希望它可以让您了解为什么从哈希中检索值似乎是随机,如果您要问的话,这是因为底层数据结构不断变化对于您现在哈希中的键,您可能会返回(3, 5),即使您首先插入了5,只是因为3 在数组中首先出现。
希望这对您有所帮助。