Java 调整数组大小时应添加多少?
我正在与另一个学生进行一场竞赛,以制作最快版本的家庭作业,出于性能原因,我没有使用ArrayList(我自己调整数组的大小将基准时间从56秒缩短为4秒),但我想知道每次需要调整数组的大小时应该调整多少。具体而言,我的代码的相关部分如下:Java 调整数组大小时应添加多少?,java,arrays,optimization,Java,Arrays,Optimization,我正在与另一个学生进行一场竞赛,以制作最快版本的家庭作业,出于性能原因,我没有使用ArrayList(我自己调整数组的大小将基准时间从56秒缩短为4秒),但我想知道每次需要调整数组的大小时应该调整多少。具体而言,我的代码的相关部分如下: TL;DR:我应该做什么?建议在调整数组大小时将数组的大小增加一倍。将规模扩大一倍会导致摊销线性时间成本 天真的想法是,调整大小值有两个相关成本: 复制性能成本—将元素从以前的阵列复制到新阵列的成本,以及 内存开销成本—分配的未使用内存的成本 如果通过一次
TL;DR:我应该做什么?建议在调整数组大小时将数组的大小增加一倍。将规模扩大一倍会导致摊销线性时间成本 天真的想法是,调整大小值有两个相关成本:
- 复制性能成本—将元素从以前的阵列复制到新阵列的成本,以及
- 内存开销成本—分配的未使用内存的成本
ArrayList
扩展了(3/2)。这使得它的内存更为保守,但在复制方面成本更高。为您的使用进行基准测试不会有什么坏处
小修正:加倍将使成本调整线性摊销,但将确保您有一个摊销固定时间插入。检查。如果您大致知道将有多少项,那么将数组或ArrayList预先指定为该大小,您就永远不必展开。无与伦比的表现
如果做不到这一点,实现良好的摊余成本的合理方法是保持一定的百分比。100%或50%是常见的。您应该将列表的大小调整为以前大小的倍数,而不是每次添加一个常量 例如:
newSize = oldSize * 2;
不是
每次需要调整大小时,请将大小加倍,除非您知道或多或少最好
如果内存不是问题,那么从一个大数组开始就可以了。为了获得最佳性能,您需要尽可能少地调整大小。将初始大小设置为通常需要的大小,而不是从N个元素开始。在这种情况下,您为N选择的值无关紧要
如果要创建大量大小不同的列表对象,则需要使用基于池的分配器,在退出之前不要释放内存
为了完全消除复制操作,您可以使用数组列表您的代码似乎与ArrayList的功能非常相似-如果您知道您将使用一个大的列表,您可以在创建列表时传递一个初始大小,并完全避免调整大小。当然,这是假设您追求的是原始速度,内存消耗不是问题。3/2很可能被选为“干净分割但小于的东西”。早在2003年11月,我们就在探索phi如何在为first fit分配器重新分配时确定重用以前分配的存储的上限
有关phi在该问题上的应用,请参见其中一个答案的注释:
问题是,内存不是一个简单的问题 问题,但我在读一本书 大文件 试试这个:
new ArrayList<Node>((int)file.length());
newarraylist((int)file.length());
您也可以使用阵列执行此操作。那么在这两种情况下都不应该调整大小,因为数组将是文件的大小(假设文件不再是int…。这里有一个类比,很久以前,当我在大型机上工作时,我们使用了一个名为VSAM的归档系统,这需要您指定初始文件大小和所需的自由空间量 每当自由空间量降至所需阈值以下时,所需的自由空间量将在程序继续处理时在后台分配
如果能在java中使用单独的线程来分配额外的空间并在主线程继续处理的同时将其“附加”到数组的末尾,这将是一件有趣的事情。
new
是一个合法的变量名(在add()声明中)?Oops。我想说的是newNode。问题是内存不是问题,但我正在读取一个任意大的文件。我也在提交这个文件,所以让list=new Node[Integer.MAX_VALUE]可能会让老师不高兴。这也可能会比系统有更多内存。我会从更温和的东西开始,比如1024或2048;vs新ArrayList(1000);而我的速度快了约100倍。好主意,我没有想到设置初始大小。看起来很奇怪,但我怀疑ArrayList可能有一些健全的检查来减慢它的速度。@Brendan您的基准测试结果似乎非常奇怪。查看ArrayList的源代码,至少在我的OpenJDK1.6.0上是这样,它与您所做的完全一样;计算新容量(与复制阵列的成本相比可以忽略不计)。这是我的测试脚本:还有我的数组类:在我的计算机上,ArrayList花费了大约2.5秒,而我的数组花费了0.2秒。我真的不知道为什么。。我正在使用Sun JDK。我还尝试将第二个更改为list=Arrays.copyOf(list,size*3/2)代码>并没有什么不同。我在代码中使用了将大小加倍的想法,并对其进行了基准测试,新的ArrayList(1000)比初始大小为1000的代码慢了大约100倍;如果以前分配的空间仍然可用,则加倍可防止使用该空间。因子phi定义了
newSize = oldSize + N;
new ArrayList<Node>((int)file.length());