Java:测试数组求和算法效率

时间:2016-05-14 23:53:43

标签: java arrays algorithm recursion

我正在读大学的Java课程,我的笔记给了我3种方法来计算ArrayList的总和。首先使用迭代,第二次使用递归,第三次使用数组拆分与递归相结合。

我的问题是如何测试这些算法的效率?实际上,我认为算法计算值所需的步骤数就是告诉你算法效率的原因。

3种算法的代码:

import java.util.ArrayList;
public class ArraySumTester {

    static int steps = 1;

    public static void main(String[] args) {

        ArrayList<Integer> numList = new ArrayList<Integer>();

        numList.add(1);
        numList.add(2);
        numList.add(3);
        numList.add(4);
        numList.add(5);


        System.out.println("------------------------------------------");
        System.out.println("Recursive array sum = " + ArraySum(numList));

        System.out.println("------------------------------------------");
        steps = 1;
        System.out.println("Iterative array sum = " + iterativeSum(numList));

        System.out.println("------------------------------------------");
        steps = 1;
        System.out.println("Array sum using recursive array split : " + sumArraySplit(numList));

    }

    static int ArraySum(ArrayList<Integer> list) {
        return sumHelper(list, 0);
    }

    static int sumHelper(ArrayList<Integer> list, int start) {
        // System.out.println("Start : " + start);
        System.out.println("Rescursive step : " + steps++);
        if (start >= list.size())
            return 0;
        else
            return list.get(start) + sumHelper(list, start + 1);

    }

    static int iterativeSum(ArrayList<Integer> list) {
        int sum = 0;
        for (Integer item : list) {
            System.out.println("Iterative step : " + steps++);
            sum += item;
        }
        return sum;
    }

    static int sumArraySplit(ArrayList<Integer> list) {

        int start = 0;
        int end = list.size();
        int mid = (start + end) / 2;

        System.out.println("Rescursive step : " + steps++);
        //System.out.println("Start : " + start + ", End : " + end + ", Mid : " + mid);
        //System.out.println(list);

        if (list.size() <= 1)
            return list.get(0);
        else
            return sumArraySplit(new ArrayList<Integer>(list.subList(0, mid)))
                    + sumArraySplit(new ArrayList<Integer>(list.subList(mid,
                            end)));

    }
}

输出:

------------------------------------------
Rescursive step : 1
Rescursive step : 2
Rescursive step : 3
Rescursive step : 4
Rescursive step : 5
Rescursive step : 6
Recursive array sum = 15
------------------------------------------
Iterative step : 1
Iterative step : 2
Iterative step : 3
Iterative step : 4
Iterative step : 5
Iterative array sum = 15
------------------------------------------
Rescursive step : 1
Rescursive step : 2
Rescursive step : 3
Rescursive step : 4
Rescursive step : 5
Rescursive step : 6
Rescursive step : 7
Rescursive step : 8
Rescursive step : 9
Array sum using recursive array split : 15

现在从上面的输出中,递归数组拆分算法占用了大部分步骤,但是根据我的说明,它与迭代算法一样有效。那么哪些不正确我的代码或我的笔记?

5 个答案:

答案 0 :(得分:1)

使用System.currentTimeMillis()是可行的方法。在代码之前定义一个起始变量,在完成之后定义一个结束变量。这些差异将是程序执行所用的时间。最短的时间将是最有效的。

long start = System.currentTimeMillis();

//程序测试

long end = System.currentTimeMillis(); long diff = end - start;

答案 1 :(得分:1)

您是否只想查看执行速度?如果是这样,您将要查看微基准测试: How do I write a correct micro-benchmark in Java?

基本上由于JVM和现代处理器的工作原理,通过在FOR循环中运行一百万次并使用系统计时器(EDIT)测量执行速度,您不会获得一致的结果。

那说,&#34;效率&#34;也可以指内存消耗等其他内容。例如,任何递归方法都存在堆栈溢出的风险,此站点以此命名的问题:)尝试给出ArrayList成千上万的元素,看看会发生什么。

答案 2 :(得分:1)

我建议您在摘要中查看这些算法的运行时间和空间复杂度(这些是计算机科学的名称,以提高效率)。这就是所谓的Big-Oh notation

确切地说,当然,在实现和尽可能无副作用之后,您应该考虑编写微基准。

由于您必须能够读取列表中每个元素的值以便对这些元素求和,无算法的性能优于(线性){{1}时间,O(n)空间算法(这是你的迭代算法所做的)在一般情况下(即没有任何其他假设)。这里O(1)是输入的大小(即列表中元素的数量)。据说这样的算法具有线性时间恒定空间复杂性,这意味着它的运行时间随着列表大小的增加而增加,但它不 em>需要任何额外的内存;事实上,它需要一些常量内存来完成它的工作。

另外两个递归算法,最多也可以执行这个简单的算法,因为迭代算法没有任何复杂性(例如堆栈上的额外内存),递归算法会受到影响。

这反映在具有相同n运行时间的算法的常量项中。例如,如果你以某种方式找到一个算法来检查列表中大约一半的元素来解决问题,而另一个算法必须看到所有的元素,那么,第一个算法有更好的常量项比第二,并且有望在实践中击败它,尽管这两种算法的时间复杂度都为O(f(n))

现在,很有可能通过将巨型列表拆分为较小的列表(您可以通过索引将效果分成单个列表)来将解决方案并行化到此问题,然后使用可能超过其他算法的并行求和操作清单足够长。这是因为每个非重叠区间可以并行(同时)求和,并且最后将部分总和相加。但这不是我们在当前背景下考虑的可能性。

答案 3 :(得分:0)

我会说使用Guava Google Core Libraries For Java秒表。例如:

Stopwatch stopwatch = Stopwatch.createStarted();
// TODO: Your tests here
long elapsedTime = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);

您可以获得所需的任何单位,并且您不需要任何额外的计算。

答案 4 :(得分:0)

如果你想考虑效率,那么你真的需要考虑算法结构而不是时间。

加载您正在使用的方法的来源,深入了解结构并寻找循环 - 这将为您提供正确的效率衡量标准。