什么是哈希表和哈希图及其典型用例?

时间:2020-03-06 14:46:17  来源:igfitidea点击:

我最近几次遇到这些术语,但是我很困惑它们的工作方式以及通常何时实施?

解决方案

好吧,这样想吧。

如果我们使用数组,一个简单的基于索引的数据结构,并用随机填充的数据填充它,那么在填充数据时,找到特定条目将变得越来越昂贵,因为我们基本上必须从以下位置开始搜索一端朝向另一端,直到找到所需的一端。

如果要更快地访问数据,通常可以对数组进行排序并使用二进制搜索。但是,这虽然提高了查找现有值的速度,但使插入新值的速度变慢,因为当我们需要在中间插入元素时,我们需要四处移动现有元素。

另一方面,哈希表具有关联的功能,该功能接受一个条目并将其减少为一个数字,即哈希键。然后,该数字将用作数组的索引,这是我们存储条目的位置。

哈希表围绕着一个数组旋转,该数组最初是空的。空并不意味着长度为零,数组以大小开始,但是数组中的所有元素都不包含任何内容。

每个元素都有两个属性,数据和一个标识数据的密钥。例如,美国的邮政编码列表将是邮政编码->关联的名称类型。该函数减少密钥,但不考虑数据。

因此,当我们在哈希表中插入某些内容时,该函数将键减少为一个数字,该数字用作该(空)数组的索引,并且在此存储数据,键和关联数据。

然后,稍后,我们想找到一个我们知道该键的特定条目,因此我们可以通过相同的函数运行该键,获取其哈希键,然后转到哈希表中的该特定位置并在其中检索数据。

从理论上讲,将键简化为哈希键(即数字)的功能在计算上比线性搜索便宜得多。

典型的哈希表没有无限个可用于存储的元素,因此通常将其数量进一步减少到适合数组大小的索引。一种方法是简单地将索引的模数与数组的大小进行比较。对于大小为10的数组,索引0-9将直接映射到索引,索引10-19将再次映射到0-9,依此类推。

某些键将减少为与哈希表中现有条目相同的索引。在这一点上,直接比较实际的键,以及与比较键的数据类型相关的所有规则(例如,普通字符串比较)。如果完全匹配,则可以忽略新数据(它已经存在)或者覆盖(为该键替换旧数据),或者添加它(多值哈希表)。如果没有匹配项,这意味着尽管哈希键是相同的,但实际的键并不相同,通常我们会找到一个新位置来存储该键和数据。

冲突解决方案有很多实现,最简单的实现是只转到数组中的下一个空元素。但是,这种简单的解决方案还有其他问题,因此,找到合适的分辨率算法对于哈希表也是一个很好的选择。

如果散列表完全(或者接近)填满,散列表也可能会增长,这通常是通过创建一个新大小的新数组,并再次计算所有索引,然后将项目放入新数组中来实现的。位置。

将键减小为数字的函数不会产生线性值,即。 " AAA"变为1,然后" AAB"变为2,因此哈希表未按任何典型值进行排序。

这里也有关于该主题的出色维基百科文章。

哈希表/哈希图将一个值(出于消歧目的称为"键")与另一个值相关联。我们可以将它们视为字典(单词:定义)或者数据库记录(键:数据)。

如果我们是用Java讲的话,这两个都是允许对象添加,删除和更新并在内部使用Hasing算法的集合。

但是,如果我们参考Java进行讨论,则最大的不同在于,哈希表本质上是同步的,因此是线程安全的,而哈希映射不是线程安全的集合。

除了同步之外,在两种情况下,存储和检索对象的内部机制都是散列。

如果我们需要了解散列的工作原理,我建议我们对数据结构和散列技术进行一些谷歌搜索。

lassevk的回答很好,但可能包含太多细节。这是执行摘要。我特意忽略了某些相关信息,我们可以安全地在99%的时间内忽略这些信息。

哈希表和哈希映射之间99%的时间没有重要区别。

哈希表是不可思议的

严重地。它是一个神奇的数据结构,几乎可以保证三件事。 (有例外。尽管有一天学习它们可能对我们有用,但是我们可以在很大程度上忽略它们。)

1)哈希表中的所有内容都是一对的一部分-有一个键和一个值。我们可以通过指定要操作的键来放入和取出数据。

2)如果我们通过哈希表上的单个键执行任何操作,那将非常快。这意味着put(key,value),get(key),contains(key)和remove(key)都非常快。

3)通用哈希表无法执行#2中未列出的任何操作! (通过"失败",我们表示它们非常慢。)

我们什么时候使用哈希表?

当哈希表适合我们的问题时,我们将使用哈希表。

例如,缓存经常最终会使用哈希表-例如,假设我们在一所大学中有45,000名学生,并且某些过程需要保留所有学生的记录。如果我们通常用ID号来指代学生,那么ID => student缓存非常有意义。我们为此缓存优化的操作是快速查找。

当我们不想全力以赴地改变对象本身时,哈希对于存储数据之间的关系也非常有用。例如,在课程注册期间,使学生与他们正在参加的课程联系起来可能是一个好主意。但是,无论出于何种原因,我们可能都不希望Student对象本身对此有所了解。使用" studentToClassRegistration"哈希值,并在执行所需的操作时将其保留。

除了需要执行以下操作之一外,它们还是数据结构的不错选择:

何时不使用哈希表

遍历元素。哈希表通常不能很好地进行迭代。 (泛型的。也就是说,特定的实现有时包含链接列表,这些链接列表用于使对其进行迭代的吸收减少。例如,在Java中," LinkedHashMap"可让我们快速迭代键或者值。)

排序。如果我们不能迭代,那么排序也是一种痛苦。

从价值到关键。使用两个哈希表。相信我,我为我们省去了很多痛苦。