【问题标题】:LinkedHashMap Implementation in JavaJava中的LinkedHashMap实现
【发布时间】:2015-06-20 23:25:13
【问题描述】:

我无法理解 LinkedHashMapHashFunction 的使用。

在HashMap实现中,hashFunction的使用是寻找内部数组的索引,可以说得通,遵循hashfunction契约(同键必须具有相同的哈希码,但不同的键可以具有相同的哈希码)。

我的问题是:

1)LinkedHashMap中的hashfunction有什么用?

2) put 和 get 方法如何用于LinkedHashMap

3) 为什么它在内部维护双链表? 使用HashMap 作为内部实现有什么问题(就像HashSet)并在插入序列中维护一个单独的Entry 数组 索引的Array/List ?

欣赏有用的回复和参考。

【问题讨论】:

    标签: java linkedhashmap


    【解决方案1】:

    1) LinkedHashMap 扩展了 HashMap,因此哈希函数与 HashMap 相同(如果您检查代码,哈希函数是从 HashMap 继承的),即该函数计算插入对象的哈希值并用于存储数据结构与具有相同键散列的元素一起;在 get 方法中使用 hasfunction 来检索具有指定为参数的键的对象。

    2)Put 和 Get 方法的行为方式与 HashMap 相同,并且跟踪元素的插入顺序,因此当您遍历键集时,您会按照插入映射的顺序获取键值(请参阅 @987654321 @了解更多详情)

    3) LinkedHashMap 使用双链表而不是数组,因为它更紧凑;双链表是插入和删除项目的最有效的列表数据结构;如果您主要插入/附加元素,那么基于数组的实现可能会更好。由于映射语义是键值实现,并且从映射中删除元素可能是一种频繁的操作,因此双链表更适合。可以使用 LinkedList 进行内部实现,但我的意见是使用低级数据结构更有效,并将 LinkedHashMap 与其他类解耦。

    【讨论】:

      【解决方案2】:

      LinkedHashMap确实使用HashMap(实际上它是从它扩展而来的),因此hashCode 用于在哈希桶数组中识别正确的哈希桶,只是至于HashMapputgetHashMap 一样工作(除了用于迭代条目的 beforeafter 引用在两种实现中的更新不同)。

      保留ArrayArrayList 不保留插入顺序的原因是,在ArrayList 中间添加或删除是O(n) 操作,因为您必须将所有后续项目移动到一个位置.您可以使用LinkedList 来执行此操作,因为在LinkedList 中间的添加和删除是O(1)(您所要做的就是断开一些链接并创建一些新链接)。但是,使用单独的 LinkedList 没有意义,因为您也可以让 Map.Entry 对象引用上一个和下一个 Entry 对象,这正是 LinkedHashMap 的工作原理。

      【讨论】:

      • 感谢您的回答,因此为了优化时间复杂度,他们在空间复杂度方面做出了妥协。我的观点是,由于用户无法指定插入的位置,因此 put 方法将在尾部插入对象。因此,对于这种情况,ArrayList 也具有相同的复杂性
      • @SashiKant 你对空间复杂性的看法是正确的。我读到LinkedHashMap 是标准集合中最需要内存的集合之一。不过它真的很快。您可以比普通的HashSet 更快地迭代LinkedHashSet。如果您希望自己能够控制顺序,您确实需要维护一个单独的List,但正如@TimBiegeleisen 指出的那样,尝试保持两个数据结构同步通常是一个非常糟糕的主意。
      • 是的,这两种方法各有利弊。他们选择了 LinkedList。感谢您是否也可以回答我的问题 1 和 2 :)
      • @SashiKant 我以为我已经回答了 1) 和 2)?
      • 所以如果我错了请纠正我,putget 方法与HashMap 相同。差异存在于条目对象中,它有两个引用作为其实例变量,指向其上一个和下一个元素(序列)。我将非常感谢您,如果您能强调我在调用 putgetentrySet 方法时会发生什么。我认为投反对票的人没有勇气为自己的行为辩护。再次感谢您的回复
      【解决方案3】:

      LinkedHashMap 是一个很好的数据结构选择,您希望能够在运行时间为O(1) 的情况下使用putget 条目,但您还需要LinkedList 的行为。内部散列函数允许您使用恒定时间的 putget 条目。

      这里是你如何使用LinkedHashMap

      Map<String, Double> linkedHashMap = new LinkedHashMap<String, String>();
      linkedHashMap.put("today", "Wednesday");
      linkedHashMap.put("tomorrow", "Thursday");
      String today = linkedHashMap.get("today"); // today is 'Wednesday'
      

      有几个反对使用简单的HashMap 并为插入顺序维护单独的List 的论据。首先,如果你走这条路,这意味着你将不得不维护 2 个数据结构而不是一个。这很容易出错,并使维护代码更加困难。其次,如果你必须让你的数据结构线程安全,这对于 2 个数据结构来说会很复杂。另一方面,如果你使用LinkedHashMap,你只需要担心这个单一的数据结构是线程安全的。

      至于实现细节,当您将put 转换为LinkedHashMap 时,JVM 将获取您的密钥并使用加密映射函数最终将该密钥转换为存储您的值的内存地址。使用给定键执行get 也将使用此映射函数来查找内存中存储值的确切位置。 entrySet() 方法返回一个由LinkedHashMap 中的所有键和值组成的Set。根据定义,集合是无序的。 entrySet() 不保证是线程安全的。

      【讨论】:

      • 是的,这两种方法各有利弊。他们选择了LinkedList。感谢您是否也可以回答我的问题 1 和 2 :)
      • @SashiKant 我回答了第 1 部分和第 2 部分......如果我知道的话,我会遗漏什么?
      • 你的回答很有帮助,所以如果我错了,请纠正我,putget 方法与HashMap 相同。差异存在于条目对象中,它有两个引用作为其实例变量,指向其上一个和下一个元素(序列)。我会非常感谢你,如果你能强调我会发生什么,当putgetentrySet方法被调用时。再次感谢您的回复:)
      • @TimBiegeleisen 现在你的答案被否决了!这太荒谬了。
      • @SashiKant 你需要阅读源代码。这是天才的作品(但在 cmets 中解释得太复杂了)。 LinkedHashMap 实际上只覆盖了 HashMap 中的 4 个方法,尽管行为完全不同。维护 beforeafter 条目的是 Map.Entry 对象。
      【解决方案4】:

      回答。 2) 当我们调用linkedhashmap的put(map,key)时。它在内部调用 createEntry

      void createEntry(int hash, K key, V value, int bucketIndex) {
      HashMap.Entry<K,V> old = table[bucketIndex];
      Entry<K,V> e = new Entry<K,V>(hash, key, value, old);
      table[bucketIndex] = e;
      e.addBefore(header);
      size++;
      

      答案 3) 为了有效地维护linkedHashmap,你实际上需要一个双向链表。

      依次考虑三个条目

      A ---> B ---> C

      假设您要删除 B。显然 A 现在应该指向 C。但是除非您知道 B 之前的条目,否则您无法有效地说明哪个条目现在应该指向 C。要解决此问题,您需要条目指向两个像这样的方向

      ---> --->

      A B C

      这样,当您删除 B 时,您可以查看 B 之前和之后的条目(A 和 C)并进行更新,以使 A 和 C 相互指向。 之前讨论过的此链接中的类似帖子

      why linkedhashmap maintains doubly linked list for iteration

      【讨论】:

      • 有人在没人看的时候把手指伸进蜂蜜罐里……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      • 2015-02-13
      • 2013-11-13
      • 2011-03-02
      相关资源
      最近更新 更多