Java 为什么数组比ArrayList快得多?
最近,我试图解决这个问题。为此,我首先创建了一个包含所有丰富数字的列表,称为Java 为什么数组比ArrayList快得多?,java,performance,Java,Performance,最近,我试图解决这个问题。为此,我首先创建了一个包含所有丰富数字的列表,称为丰富数 接下来,我迭代这个列表,并构建另一个列表,其中包含低于某个限制的大量数字的总和。现在我注意到了一些奇怪的事情。我使用嵌套循环在列表上迭代两次。但是,如果我使用数组存储总和,需要几秒钟的时间,如果我将总和添加到ArrayList,则需要几个小时。原因是什么?我认为代价高昂的操作是两个嵌套循环,但代价高昂的操作似乎是ArrayList#add。有什么线索说明为什么会这样吗 下面是数组的代码: for (int i =
丰富数
接下来,我迭代这个列表,并构建另一个列表,其中包含低于某个限制的大量数字的总和。现在我注意到了一些奇怪的事情。我使用嵌套循环在列表上迭代两次。但是,如果我使用数组存储总和,需要几秒钟的时间,如果我将总和添加到ArrayList,则需要几个小时。原因是什么?我认为代价高昂的操作是两个嵌套循环,但代价高昂的操作似乎是ArrayList#add。有什么线索说明为什么会这样吗
下面是数组的代码:
for (int i = 0; i < abundants.size(); i++) {
for (int j = 0; j < abundants.size(); j++) {
int tot = abundants.get(i) + abundants.get(j);
if (tot <= limit)
isSum[tot] = true;
}
}
}
for(int i=0;i if(tot因为int
比Integer
快得多
尝试在第一种情况下使用Integer[]
,或者在第二种情况下使用TIntArrayList
进行比较。您的ArrayList实现是O(n^3),而另一种是O(n^2):sums.contains(…)
必须为内部循环的每次迭代遍历整个sums
列表。如果您知道(最大值)元素数,尝试使用给定大小初始化数组列表:
ArrayList<Integer> sums = new ArrayList<Integer>(abundants.size() * abundants.size());
ArrayList sums=新的ArrayList(abundants.size()*abundants.size());
这样就不必调整ArrayList的大小,这将提高速度。您的代码不是等效的,.contains()
比您使用原始数组的成本更高。.contains()
每次调用时都会遍历整个数组,但在基于原始数组的版本中不会这样做。我认为问题在于数组列表#contains
,它必须遍历整个列表,从而将复杂性提高到O(n^3),而不是O(n^2)程序的#1。我不是专家,但取决于包含的大小()
如果不能执行二进制搜索,可能会变得昂贵。是的,但这是几秒钟而不是几小时的原因吗?使用BitSet
会更好。这是因为Java没有生成int、long、float和其他一级对象……虽然int
比Integer
更快,但需要extremely
特殊情况会导致减速3000倍(如问题中所述,小时与秒)@meriton,这是真的。我没有抓住这一点。根据情况,改善的可能性更大,可能是20%到300%。一般的规则是,在比较两件事时,要逐个比较,不要以不同的方式使用。;)contains()仍然需要遍历整个ArrayList,因此速度的提高是有限的。最好尝试将运行时复杂性从O(n^3)更改为更合理的。请您添加一个可能的解决方案(如果您知道的话),因为我对此也很感兴趣。@Bobby,@Roflcoptr,if(!sums.contains(s)&&s
应该是如果(这真的能成为几秒钟而不是几小时的原因吗?这真的取决于所有这些列表有多大,但可以是!)所以…如果你有20000个元素在丰富的
中,你将经历20000*20000次。对于每一次,你都在做一些事情。如果你在最坏的情况下,在每一次迭代中多做20000个操作,这可能需要数小时或数天。
ArrayList<Integer> sums = new ArrayList<Integer>(abundants.size() * abundants.size());