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

时间:2008-09-26 08:19:33

标签: language-agnostic hashtable hashmap

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

4 个答案:

答案 0 :(得分:67)

好吧,这样想吧。

如果你使用一个数组,一个简单的基于索引的数据结构,并用随机的东西填充它,当你用数据填充它时,找到一个特定的条目会变得越来越昂贵,因为你基本上必须开始从一端向另一端搜索,直到找到你想要的那个。

如果您希望更快地访问数据,您通常需要对数组进行排序并使用二进制搜索。然而,这在提高查找现有值的速度的同时,使得插入新值变慢,因为当您需要在中间插入元素时需要移动现有元素。

另一方面,哈希表具有一个相关的函数,它接受一个条目,并将其减少为一个数字,一个哈希键。然后将此数字用作数组的索引,这是存储条目的位置。

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

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

因此,当您在哈希表中插入内容时,该函数会将键减少为一个数字,该数字用作此(空)数组的索引,这是存储数据的位置,包括键和关联数据数据

然后,您希望找到一个您知道密钥的特定条目,因此您通过相同的函数运行密钥,获取其哈希密钥,然后转到哈希表中的特定位置并检索数据那里。

该理论认为,将密钥减少到哈希密钥的函数(数字)在计算上比线性搜索便宜得多。

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

某些键将缩减为与哈希表中现有条目相同的索引。此时,直接比较实际密钥,所有规则与比较密钥的数据类型(例如,正常字符串比较)相关联。如果存在完全匹配,则要么忽略新数据(它已经存在),要么覆盖(替换该键的旧数据),或者添加它(多值哈希表)。如果没有匹配,这意味着尽管散列键相同,但实际的键不是,您通常会找到一个新位置来存储该键+数据。

碰撞分辨率有很多实现,最简单的就是转到数组中的下一个空元素。这个简单的解决方案还有其他问题,因此找到正确的解析算法也是哈希表的一个很好的练习。

Hashtables也可以增长,如果它们完全填满(或接近),这通常是通过创建新大小的新数组,再次计算所有索引,并将项目放入新数组来完成的在他们的新地点。

将键减少到数字的函数不会产生线性值,即。 “AAA”变为1,然后“AAB”变为2,因此散列表不按任何典型值排序。

关于这个主题,还有一篇很好的维基百科文章here

答案 1 :(得分:50)

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允许您快速迭代键或值。)

排序。如果您无法进行迭代,排序也是一种巨大的痛苦。

从值到键。使用两个哈希表。相信我,我只是为你节省了很多痛苦。

答案 2 :(得分:4)

如果您正在谈论Java,两者都是允许对象添加,删除和更新的集合,并在内部使用Hasing算法。

然而,如果我们参考Java,那么重要的区别是哈希表本质上是同步的,因此是线程安全的,而哈希映射不是线程安全的集合。

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

如果您需要了解Hashing的工作原理,我建议您在Google Structers和散列技术上进行一些Google搜索。

答案 3 :(得分:-2)

Hashtables / hashmaps将一个值(用于消除歧义目的称为“key”)与另一个值相关联。您可以将它们视为字典(单词:定义)或数据库记录(键:数据)。