非常大的Java ArrayList具有较慢的遍历时间

时间:2016-03-03 04:48:42

标签: java algorithm performance arraylist linked-list

解决方案:我的ArrayList填充了重复项。我修改了我的代码以过滤掉这些,这将运行时间减少到大约1秒。

我正在研究一个需要我查看大量数据的算法项目。

我的程序有一个非常大的ArrayList(A),它遍历了每个元素。对于(A)中的每个元素,将若干其他计算元素添加到另一个ArrayList(B)中。 (B)将远远大于(A)。

一旦我的程序运行了七个这样的ArrayLists,运行时间就会增加到大约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,

3 个答案:

答案 0 :(得分:2)

当某些事情变得缓慢时,典型的建议是对其进行分析。这通常是明智的,因为即使对于性能专家来说,通常也很难确定导致缓慢的原因。有时可以选择可能是性能问题的代码,但这是偶然的。此代码中有一些可能的内容,但很难确定,因为我们没有orderPrime()primeLoop()方法的代码。

那说,有一件事引起了我的注意。这一行:

    currentVal = Integer.parseInt(current.get(k).toString());

这会从current获取一个元素,将其转换为字符串,将其解析回int,然后将其装入Integer。转换为String和从String转换是非常昂贵的,并且它分配内存,因此它对垃圾收集施加压力。拳击原始int值到Integer个对象也会分配内存,从而导致GC压力。

由于您使用原始类型ArrayList作为current,因此很难说出修复的内容。我猜测它可能是ArrayList<Integer>,如果是这样,你可以用

替换这一行
    currentVal = (Integer)current.get(k);

你应该使用泛型来避免演员表。 (但这不会影响性能,只会影响代码的可读性和类型安全性。)

如果current不包含Integer值,则应该。无论它包含什么,都应该事先转换为Integer,而不是将转换放在循环中。

修复此问题后,您仍然需要进行装箱/拆箱开销。如果性能仍然存在问题,则必须从ArrayList<Integer>切换到int[],因为Java集合不能包含基元。这很不方便,因为您必须实现自己的类似列表的结构,模拟int的可变长度数组(或找到执行此操作的第三方库)。

但即使以上所有方法都可能还不足以让你的程序运行得足够快。我不知道你的算法在做什么,但看起来它正在进行线性搜索。有多种方法可以加快搜索速度。但是另一位评论者建议二元搜索,你说这是不允许的,所以不清楚这里可以做些什么。

答案 1 :(得分:1)

  1. 为什么你有这一行

    current.iterator();

  2. 你根本不使用迭代器,你甚至没有变量。这只是时间的推移。

    1. for(int k = 0; k <= current.size()-1; k++)
    2. 不是每次迭代计算大小,而是创建如下的值:

      int curSize = current.size() - 1;
      

      并在循环中使用它。

      它可以节省一些时间。

答案 2 :(得分:1)

  

以下是关于ArrayList如何发展的想法:2,29,249,2293,20727,190819

您的next列表变得过大,因此必须包含重复项:

  • 190_819个100_000个数字的条目?
  • 根据primes.utm.edu/howmany.html,只有9,592个素数达到100_000。

删除重复项肯定会缩短您的响应时间。