哈希表是一种可以将键映射到值的数据结构。给定一个密钥,哈希函数将计算然后告诉我们存储该值的槽/桶的索引。如果多个键映射到同一个插槽,它可能会从此插槽启动链接列表。如果没有足够的值插槽,它将进行调整大小操作以找到更大的空间。
{:name => "Wix", :age => 18}
等哈希对象是否算作哈希表?如果是的话,我需要问题2的答案。答案 0 :(得分:4)
ruby名称哈希有点误导。对于大多数开发人员来说,他们实际上是 maps ,这意味着你给他们一个值,他们给你另一个相关的价值。它们是 hash 映射的事实实际上只是一个实现细节,使它们更快,实际上它与hashsets的原理相同,给定一个值,只告诉你值是否在集合与否。
为了简化它,想象一下:
你有一个包含10个元素的数组。你被告知要记住35 =“一些数据”。然后哈希索引(35),我将其简化为模数除以数组长度,因此结果为35 % 10 = 5
。
然后我们在该索引处存储数据35 =“某些数据”,例如作为元组[35,“某些数据”]。
然后我们得到更多数据,25 =“更多数据”,78 =“酷东西”。同样,我们对密钥进行哈希并获得5
和8
。存储第二个很容易,我们只需将[78,“很酷的东西”]存储在数组中的第8位。
但是存储[25,“更多数据”]是一个问题,因为位置5
已经存在一个存储桶。正如您已经指出的那样,通过存储链表来解决这个问题。所以我们回到开头,然后将[35,“some data”,nil]存储为我们的第一个值。
要插入25
,我们只需更改它,以便第一个元素指向第二个元素,然后获取array[5] = [35, "some data", <pointer>] -> [25, "more data", nil]
一段时间后,用户想知道与“25”相关的值是什么。
由于我们实现了一个hashmap,我们只需哈希值25 % 10 = 5
,并知道我们的对存储在5
位置。然后我们只必须迭代一个包含2个元素的链表,查找值[25]
,当我们找到它时,只需取第二个值并将其返回给用户。
以上是一个过于简单的例子,但它显示了哈希映射如何运作的基本思路。
在现实世界中,散列算法当然比模除法更复杂,但想法是一样的。密钥的哈希值总是变成数组中的索引。一个好的哈希算法应该是1.快速和2.随机,以避免有很多空桶和一些有很多元素的桶。
另外,我们的数组不会有10的固定长度,但要聪明一点并尝试通过不过大来节省内存,但同时对内存足够慷慨以避免不必要的缩小/一直在增长,并保持合理的短暂。
在最好的情况下,你可以拥有一个数千个元素的地图,并且可以访问一个你只需要哈希的地图,这个时间与哈希的大小无关,而不是必须迭代所有数千个元素并将每个元素与您正在寻找的元素进行比较。
关于你的第三个问题,答案是肯定的。
至于第二个,密钥在存储桶中存储,但可能就像它们的散列值一样。
我不确定ruby内部如何存储这些存储桶,但通常它们可以通过多种方式实现,如数组,结构等。