为什么Java ArrayLists不会自动缩小

时间:2017-01-30 10:32:46

标签: java arraylist resize

很久以前,我观看了普林斯顿课程MOOC的视频讲座:算法简介,可以找到here。它解释了在添加或删除元素时调整ArrayList类似结构的成本。事实证明,如果我们想要为我们的数据结构调整大小,我们将从O(n)转到amortized O(n)进行addremove操作。

我使用Java ArrayList已经有好几年了。我一直都很确定它们会自动增长和缩小。就在最近,令我惊讶的是,我在this post被证明是错的。 ArrayList不会缩小(当然,它们会增长)。

以下是我的问题:

  1. 在我看来,ArrayList中的缩小不会造成任何伤害,因为效果已经amortized O(n)。为什么Java创建者没有将此功能包含在设计中?

  2. 我知道HashMap等其他数据结构也不会自动收缩。 Java中是否有任何其他数据结构构建在支持自动收缩的数组之上?

  3. 其他语言的趋势是什么?如果列表,词典,地图,Python / C#中的集合等自动收缩看起来如何。如果它们与Java所做的相反,那么我的问题是:为什么?

2 个答案:

答案 0 :(得分:3)

评论已经涵盖了你所要求的大部分内容。这里有一些关于你的问题的想法:

  1. 在Java中创建类似ArrayList的结构时,开发人员会对运行时/性能做出某些决定。他们显然决定将“正常”操作中的收缩排除在外,以避免需要额外的运行时间。

  2. 问题是您希望自动缩小的原因。 ArrayList增长不多(因素约为1.5;准确度为newCapacity = oldCapacity + (oldCapacity >> 1))。也许你也插入中间而不只是追加到最后。然后LinkedList(不基于数组 - >不需要收缩)可能会更好。这真的取决于你的用例。如果你认为你真的需要ArrayList所做的一切,但是在删除元素时它必须缩小(我怀疑你真的需要这个),只需扩展ArrayList并覆盖这些方法。不过要小心!如果您在每次移除时缩小,则返回O(n)

  3. C#List和C ++ vector在删除元素时缩小列表的行为相同。但自动增长的因素各不相同。甚至一些Java实现也使用不同的因素。

答案 1 :(得分:1)

自动收缩的另一个问题是,您可能会陷入真正可怕的“病理”情况,其中每次插入和删除列表都会导致后备阵列的增加或收缩。

例如,如果后备阵列的初始容量为10,使得该阵列在插入第11个元素时会增加(容量将增加到15),那么自然的实现是一旦列表大小就缩小后备阵列跌至11以下。如果您的列表长度在10到11之间变化,那么您将不断更改支持数组。不仅会增加运行时的开销,而且如果每个操作导致10个或15个对象成为垃圾,您可能会开始对垃圾收集器施加很大压力。