当两个对象放在哈希表的同一个存储桶中时,为什么Hashmap
在内部使用LinkedList
而不是Arraylist
?
答案 0 :(得分:13)
为什么
HashMap
内部使用sLinkedList
而不是Arraylist
,当两个对象放在哈希表的同一个桶中时?
实际上,它也没有使用(!)。
它实际上使用通过链接哈希表条目实现的单链表。 (相比之下,LinkedList
是双重链接的,并且它需要为列表中的每个元素分别使用Node
个对象。)
那我为什么要在这里挑剔呢?因为它实际上很重要...因为这意味着LinkedList
和ArrayList
之间的正常权衡不适用。
正常的权衡是:
ArrayList
占用的空间较少,但在最糟糕的情况下,所选元素的插入和移除为O(N)
。
LinkedList
占用的空间更多,但所选元素的插入和移除为O(1)
。
但是,对于通过将HashMap
条目节点链接在一起形成的私有单链表,空间开销是一个引用(与ArrayList
相同),插入节点的成本为{ {1}}(与O(1)
相同),删除所选节点的费用也是LinkedList
(与O(1)
相同)。
完全依赖"大O"对于这种分析是可疑的,但是当你查看实际的代码时,很明显LinkedList
在删除和插入的性能上击败了HashMap
,并且与查找相当。 (这忽略了内存局部效应。)并且它使用的内存比使用ArrayList
或ArrayList
的内存少......考虑到已经有内部条目对象来保存键/值对
但它变得更加复杂。在Java 8中,他们对LinkedList
内部数据结构进行了全面检查。在当前实现中,一旦哈希链超过特定长度阈值,实现就切换到使用按键值排序的数组,以及用于链内查找的二进制搜索。那时,哈希链真的更好地被视为集合而不是列表。基于如何添加条目的哈希链的任何残留排序都将丢失。 (没关系。无论如何它都没有意义或稳定。)
答案 1 :(得分:0)
简短答案:Java使用LinkedList或ArrayList(以其认为适合于数据的形式为准)。
长期回答
尽管经过排序的ArrayList看起来很明显,但是改用LinkedList有一些实际的好处。 我们需要记住,仅当键冲突时才使用LinkedList链。 但是作为哈希函数的定义:冲突应该很少见
在极少数情况下,我们必须在Sorted ArrayList或LinkedList之间进行选择。 如果我们比较排序的ArrayList和LinkedList,则有一些明显的权衡点
现在,很明显,LinkedList在插入和删除期间比排序的ArrayList更好,但是在检索时却很糟糕。
在冲突更少的情况下,排序的ArrayList带来的价值更少(但开销更大)。 但是,当冲突更加频繁且冲突元素列表变大(超过特定阈值)时,Java会将冲突数据结构从LinkedList更改为ArrayList。
答案 2 :(得分:-2)
这基本上归结为ArrayList和LinkedList的复杂性。 在LinkedList中插入(当顺序不重要时)是O(1),只是追加开始。 在ArrayList中插入(当顺序不重要时)是O(N),遍历到结尾,并且还有调整大小的开销。
删除是LinkedList中的O(n),遍历和调整指针。 arraylist中的删除可以是O(n ^ 2),遍历元素和移位元素或调整Arraylist的大小。
在任何一种情况下,包含都是O(n)。
使用HashMap时,我们期望O(1)操作可以添加,删除和包含。使用ArrayList,我们将在存储桶中添加,删除操作会产生更高的成本