非常大的 Java ArrayList 遍历时间很慢



解决方案:我的 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。

摆脱重复项肯定会改善您的响应时间。

  1. 为什么你有这条线

    current.iterator();

你根本不使用迭代器,你甚至没有它的变量。只是浪费时间。

  1. for(int k = 0; k <= current.size()-1; k++)

与其每次迭代都计算大小,不如创建如下值:

int curSize = current.size() - 1;

并在循环中使用它。

它可以节省一些时间。

相关内容

  • 没有找到相关文章

最新更新