36

我需要存储大量信息,例如 java 列表中的“名称”。项目的数量可以改变(或者简而言之我无法预定义大小)。我认为,从内存分配的角度来看,LinkedList 将是比 ArrayList 更好的选择,因为对于 ArrayList,一旦达到最大大小,内存分配会自动加倍,因此总是有可能分配比 ArrayList 更多的内存需要什么。

我从这里的其他帖子中了解到,存储在 LinkedList 中的单个元素比 ArrayList 占用更多空间,因为 LinkedList 还需要存储节点信息,但我仍然猜测我定义的场景 LinkedList 可能是更好的选择。另外,我不想进入性能方面(获取、删除等),因为已经讨论了很多。

4

5 回答 5

66

LinkedList可能会分配更少的条目,但这些条目比它们的实际成本要高得多-就内存而言ArrayList,即使是最坏的情况也会更便宜。ArrayList

(仅供参考,我认为你弄错了;ArrayList满时增长 1.5 倍,而不是 2 倍。)

参见例如https://github.com/DimitrisAndreou/memory-measurer/blob/master/ElementCostInDataStructures.txtLinkedList每个元素消耗 24 个字节,而ArrayList在最好的情况下每个元素消耗 4 个字节,在最坏的情况下每个元素消耗 6 个字节. (结果可能因 32 位与 64 位 JVM 和压缩对象指针选项而异,但在这些比较中,每个LinkedList元素至少需要 36 个字节,ArrayList最多为 8 个,最差为 12 个。)

更新:

我从这里的其他帖子中了解到,存储在 LinkedList 中的单个元素比 ArrayList 占用更多空间,因为 LinkedList 还需要存储节点信息,但我仍然猜测我定义的场景 LinkedList 可能是更好的选择。另外,我不想进入性能方面(获取、删除等),因为已经讨论了很多。

需要明确的是,即使在最坏的情况下ArrayList也比LinkedList具有相同元素的 a 小 4 倍。唯一可能的LinkedList取胜方法是通过调用ensureCapacity故意夸大的值来故意修复比较,或者在添加后删除大量值ArrayList

简而言之,LinkedList内存比较基本上是不可能取胜的,而且如果你关心空间,那么调用trimToSize()ArrayList立即ArrayList再次以巨大的优势获胜。严重地。 ArrayList获胜。

于 2012-07-19T15:44:34.800 回答
6

...但我仍然猜测我定义的场景 LinkedList 可能是一个更好的选择

你的猜测不正确。

一旦超过了数组列表的初始容量,支持的大小将在 1 到 2 个引用乘以条目数之间。这是由于用于增长后备阵列的策略。

对于链表,每个节点占用的条目数至少是条目数的 3 倍,因为每个节点都有一个nextprev引用以及条目引用。(事实上​​,它超过了 3 倍,因为节点的对象头和填充使用的空间。根据 JVM 和指针大小,它可能高达 6 倍。)

链表使用的空间比数组列表少的唯一情况是您严重高估了数组列表的初始容量。(对于非常小的列表......)


当您考虑它时,链表与数组列表相比唯一真正的优势是在插入和删除元素时。即便如此,这也取决于你如何做到这一点。

于 2012-07-19T15:45:52.987 回答
4

ArrayList 每个对象使用一个引用(或者当它的大小是所需大小的两倍时使用两个)这通常是 4 个字节。

LinkedList 只使用它需要的节点,但每个节点可以是 24 个字节。

所以即使在最坏的情况下,ArrayList 也会比 LinkedList 小 3 倍。

对于获取 AArrayList 支持随机访问 O(1) 但 LinkedList 是 O(n)。对于从末尾删除,两者都是 O(1),对于从中间 ArrayList 的某处删除是 O(n)

除非您有数百万个条目,否则集合的大小不太重要。首先重要的是条目的大小,无论使用何种集合,条目的大小都是相同的。

于 2012-07-19T15:44:04.767 回答
3

ArrayList.trimToSize()可能会让你满意。

将此 ArrayList 实例的容量修剪为列表的当前大小。应用程序可以使用此操作来最小化 ArrayList 实例的存储。

顺便说一句,在 ArrayList Java6 中,它不是双倍容量,它大约是达到最大大小的 1.5 倍。

于 2012-07-19T15:43:15.787 回答
3

信封最坏情况的背面:

一个大小为 1,000,000 = 500,000 个已使用的数组中有 500,000 个名称,分配数组的未使用部分中有 500,000 个空指针。

链表中的 500,000 个条目 = 每个条目 3 个指针(Node 对象保存 current、prev 和 next)= 内存中的 1,5000,000 个指针。(然后你必须添加节点本身的大小)

于 2012-07-19T15:47:05.017 回答