解决方案:我的 ArrayList 充满了重复项。我修改了我的代码以过滤掉这些内容,从而将运行时间减少到大约 1 秒。
我正在从事一个算法项目,需要我查看大量数据。
我的程序有一个可能非常大的 ArrayList (A),它遍历了其中的每个元素。对于 (A) 中的每一个元素,其他几个计算元素将添加到另一个 ArrayList (B) 中。(B)将比(A)大得多。
一旦我的程序运行了其中七个 ArrayList,运行时间就会增加到大约 5 秒。如果可能的话,我试图将其缩短到<1 秒。
我愿意接受遍历 ArrayList 的不同方式,以及使用完全不同的数据结构。我不关心列表中值的顺序,只要我可以非常快速地浏览所有值。我尝试过链接列表,速度明显较慢。
下面是一段代码,以便您更好地理解。该代码试图找到素数的所有个位数排列。
public static Integer primeLoop(ArrayList current, int endVal, int size)
{
Integer compareVal = 0;
Integer currentVal = 0;
Integer tempVal = 0;
int currentSize = current.size()-1;
ArrayList next = new ArrayList();
for(int k = 0; k <= currentSize; k++)
{
currentVal = Integer.parseInt(current.get(k).toString());
for(int i = 1; i <= 5; i++)
{
for(int j = 0; j <= 9; j++)
{
compareVal = orderPrime(currentVal, endVal, i, j);
//System.out.println(compareVal);
if(!compareVal.equals(tempVal) && !currentVal.equals(compareVal))
{
tempVal = compareVal;
next.add(compareVal);
//System.out.println("Inserted: "+compareVal + " with parent: "+currentVal);
if(compareVal.equals(endVal))
{
System.out.println("Separation: " + size);
return -1;
}
}
}
}
}
size++;
//System.out.println(next);
primeLoop(next, endVal, size);
return -1;
}
*编辑:从上面的代码片段中删除了不必要的代码。创建了一个currSize变量,该变量使程序不必每次都调用(当前)的大小。还是没有区别。以下是 ArrayList 如何增长的想法:2,29,249,2293,20727,190819,
当某件事很慢时,典型的建议是分析它。这通常是明智的,因为通常很难确定缓慢的原因是什么,即使对于性能专家也是如此。有时,可以挑选出可能出现性能问题的代码,但这是命中或未命中。这段代码中有一些可能的东西,但很难确定,因为我们没有orderPrime()
和primeLoop()
方法的代码。
也就是说,有一件事引起了我的注意。这一行:
currentVal = Integer.parseInt(current.get(k).toString());
这会从current
中获取一个元素,将其转换为字符串,将其解析回int
,然后将其装入Integer
。与 String 之间的转换非常昂贵,并且它会分配内存,因此会给垃圾回收带来压力。将基元int
值装箱到Integer
对象也会分配内存,从而增加 GC 压力。
很难说修复是什么,因为您正在使用原始类型ArrayList
进行current
。我推测它可能ArrayList<Integer>
,如果是这样,您可以将此行替换为
currentVal = (Integer)current.get(k);
您应该使用泛型以避免强制转换。(但这不会影响性能,只是影响代码的可读性和类型安全性。
如果current
不包含Integer
值,则它应该包含。无论它包含什么,都应该事先转换为Integer
,而不是将转换放在循环中。
修复此问题后,您仍然需要装箱/拆箱开销。如果性能仍然是一个问题,则必须从ArrayList<Integer>
切换到int[]
,因为 Java 集合不能包含原语。这很不方便,因为您必须实现自己的类似列表的结构来模拟可变长度的int
数组(或找到执行此操作的第三方库)。
但即使以上所有内容可能也不足以使您的程序运行得足够快。我不知道你的算法在做什么,但看起来它正在做线性搜索。有多种方法可以加快搜索速度。但是另一位评论者建议进行二进制搜索,而您说这是不允许的,因此不清楚这里可以做什么。
以下是 ArrayList 如何增长的想法:2、29、249、2293、20727、190819
您的next
列表变得太大,因此它必须包含重复项:
- 190_819 个条目对应 100_000 个数字?
- 根据 primes.utm.edu/howmany.html,只有9,592个素数达到100_000。
摆脱重复项肯定会改善您的响应时间。
-
为什么你有这条线
current.iterator();
你根本不使用迭代器,你甚至没有它的变量。只是浪费时间。
-
for(int k = 0; k <= current.size()-1; k++)
与其每次迭代都计算大小,不如创建如下值:
int curSize = current.size() - 1;
并在循环中使用它。
它可以节省一些时间。