【问题标题】:Storing a dictionary in a hashtable将字典存储在哈希表中
【发布时间】:2012-09-15 23:57:22
【问题描述】:

我正在处理一项任务,但我无法联系到教授来弄清楚某件事。我们的想法是,我们正在编写一个字谜求解器,使用给定的一组单词,我们将其存储在 3 个不同的字典类中:线性、二进制和哈希。

所以我们从文本文件中读取单词,对于前 2 个字典对象(线性和二进制),我们将单词存储为 ArrayList...很容易。

但是对于 HashDictionary,他希望我们将单词存储在 HashTable 中。我只是不确定 HashTable 的值是什么,或者你为什么要这样做。说明说我们将单词存储在哈希表中以便快速检索,但我只是不明白这是什么意思。将单词存储在数组列表中是有意义的,但我只是不确定键/值对如何帮助字典。

也许我没有提供足够的细节,但我想也许有人会看到这样的东西,而且对他们来说很明显。

我们的每个类都有一个 contains 方法,它返回一个布尔值,表示传入的单词是否在字典中,所以 linear 对 arraylist 进行线性搜索,binary 对 arraylist 进行二进制搜索,而且我不确定哈希....

【问题讨论】:

  • 你负责实现三个对象?线性、二进制和散列?什么是“二叉树”——二叉树?二进制搜索?您是存储单词还是字谜?
  • 抱歉,一个 LinearDictionary、一个 BinaryDictionary 和一个 HashDictionary。它们每个都从抽象类 Dictionary 扩展而来,该类具有一个名为 contains 的抽象方法,3 个类中的每一个都必须实现该方法。所以每个类通过读取文本文件来加载字典,并将单词存储在数组列表中,在线性和二进制字典的情况下,但我们被告知将单词存储在 HashTable 的 HashDictionary 中,我只是不'不明白为什么。
  • 我从未听说过“LinearDictionary”或“BinaryDictionary”。
  • @Richard 如果我不得不猜测,线性字典基本上是一个实现地图样式接口的列表,而 BinaryDictionary 基本上是一个树形图。
  • 通用标题暗示这解决了一个普遍问题,但它没有。所以这个问题引起了人们的注意,然后没有提供。因此,这不是一个好问题。 (在我看来,让标题更具体会解决这个问题。)

标签: java


【解决方案1】:

区别在于速度。两种方法都有效,但哈希表速度很快。

当您使用ArrayList 或任何类型的List 来查找元素时,您必须逐个检查每个列表项,直到找到所需的单词。如果该词不存在,则您已遍历整个列表。

当您使用HashTable 时,您会对正在查找的单词执行一些“魔术”,即计算单词的哈希值。使用该哈希值,而不是遍历值列表,您可以立即推断在哪里找到您的单词 - 或者,如果您的单词在哈希中不存在,那么您的单词就不存在。

我在这里过于简单化了,但这是一般的想法。您可以找到另一个问题here,其中包含有关哈希表如何工作的各种解释。

这是一个使用HashMap的小代码sn-p。

// We will map our words to their definitions; word is the key, definition is the value
Map<String, String> dictionary = new HashMap<String, String>();
map.put("hello","A common salutation");
map.put("chicken","A delightful vessel for protein");

// Later ...
map.get("chicken"); // Returns "A delightful vessel for protein"; 

您描述的问题要求您使用HashMap 作为满足三个要求的字典的基础:

  • 将单词添加到字典中
  • 从字典中删除一个词
  • 检查单词是否在字典中

使用存储键和值的映射似乎违反直觉,因为您真正想要的只是存储一个键(或只是一个值)。但是,如上所述,HashMap 可以非常快速地找到与键关联的值。同样,它可以非常快速地查看HashMap 是否知道密钥。我们可以通过将每个字典单词存储为HashMap 中的键并将其与垃圾值(因为我们不关心它)相关联,例如null 来利用这种质量。

您可以看到如何满足三个要求,如下所示。

Map<String, Object> map = new HashMap<String, Object>();
// Add a word
map.put('word', null);

// Remove a word
map.remove('word');

// Check for the presence of a word
map.containsKey('word');

我不想让信息过多,但我们这里的要求与称为Set 的数据结构一致。在 Java 中,一个常用的SetHashSet,这几乎正是您在这部分家庭作业中实现的。 (事实上​​,如果这不是明确指示您使用HashMap 的家庭作业,我建议您改用HashSet。)

【讨论】:

  • 一听到HashTable,我就想到了HashMap。所以条目的键是实际的单词,值是什么,它的哈希?
  • 我的回答非常笼统。我的描述适用于HashtableHashMap。这些类是为了方便而编写的;实际上,它们非常方便,您甚至根本不需要考虑他们使用哈希的事实:您只需告诉他们“我想存储 X 并将其与键 Y 关联!”它符合要求。哈希发生在幕后。
  • 对,但在这种情况下,我知道关键是实际的单词,我只是不知道生成对的值是什么。从我所见,我猜它是那个词的哈希值,但是我该如何得出哈希值呢?
  • 哦,我明白了 - 你的字典实际上不包含定义吗?它只是一个很大的单词列表,您只想知道一个单词是否在列表中?
  • cheeken,我完全理解你对地图的解释,但我的问题可能是两部分。我有一个需要存储在哈希表中的单词列表,以及每个单词的一些值。所以当我调用 mytable.put("wordA","??").我猜的??将是“wordA”的哈希?如果是这种情况,我该如何计算哈希值?有人建议在哈希表中的某个位置添加单词,但我没有看到任何允许您控制定位的方法,只是 put() 方法。
【解决方案2】:

数组很难找到东西。如果我给你array[0] = "cat"; array[1] = "dog"; array[2] = "pikachu";,你必须检查每个元素才能知道 jigglypuff 是否是一个单词。如果我给了你hash["cat"] = 1; hash["dog"] = 1; hash["pikachu"] = 1;",马上就可以了,你直接查一下就行了。在这种特殊情况下,值 1 无关紧要,尽管您可以在其中放置有用的信息,例如您查找单词的次数,或者 1 表示真实单词,2 表示口袋妖怪的名称,或者一本真正的字典,它可以包含一个句子长的定义。不太相关。

【讨论】:

    【解决方案3】:

    那听起来你并不真正了解哈希表。甚至Wikipedia 对这个数据结构都有很好的解释。

    您的哈希表将只是一个大字符串数组(最初都是空的)。您使用单词中的字符计算哈希值,然后将单词插入表中的该位置。

    当两个单词的哈希值相同时会出现问题。并且有一些解决方案。一种是在每个数组位置存储一个列表,然后将单词推到该列表中。另一种方法是按已知数量逐步浏览表格,直到找到一个空闲位置。另一种是使用不同的算法计算二级哈希。

    重点是哈希查找速度很快。计算哈希值非常快,然后您所要做的就是检查该数组位置的单词是否存在(并且与搜索单词匹配)。您遵循用于插入的哈希值冲突(在本例中为不匹配)的相同规则。

    您希望您的表格大小是一个大于您打算存储的元素数量的素数。您还需要一个快速发散的哈希函数,以便您的数据更有可能通过您的哈希表广泛分散(而不是大量聚集在一个区域中)。

    希望这对您有所帮助,并为您指明正确的方向。

    【讨论】:

    • 好的。所以当我在表格中添加一个词时,它会不会像 myhashtable.put("myword", getHash("myword"));??
    • 不,哈希表插入不需要哈希表内部知识(即哈希计算),就像有序列表不应该要求您搜索要插入的正确位置一样。你应该简单地告诉它插入这个词,它会在内部做所有杂乱无章的事情。与搜索相同:您只需询问哈希表是否包含一个单词,而无需知道其他任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 2011-04-14
    • 1970-01-01
    • 2013-03-21
    • 2012-08-23
    • 2014-01-04
    • 1970-01-01
    相关资源
    最近更新 更多