簡體   English   中英

Java:測試數組求和算法的效率

[英]Java : Testing Array Sum Algorithm Efficiency

我正在大學上一門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

現在,從上面的輸出中,遞歸數組拆分算法采取了最多的步驟,但是根據我的筆記,它與迭代算法一樣有效。 那么我的代碼或注釋中哪個不正確?

使用System.currentTimeMillis()是方法。 在代碼之前定義一個開始變量,在代碼完成之后定義一個結束變量。 這些差異將是程序執行所花費的時間。 最短的時間將是最有效的。

長期開始= System.currentTimeMillis();

//程序進行測試

長端= System.currentTimeMillis(); long diff =結束-開始;

您是否只想看看執行速度? 如果是這樣,您將需要研究微基准測試如何用Java編寫正確的微基准測試?

本質上是因為JVM和現代處理器的工作方式,通過在FOR循環中運行一百萬次並使用系統計時器(EDIT)測量執行速度,您將無法獲得一致的結果。

話雖如此,“效率”也可能意味着其他事情,例如內存消耗。 例如,任何遞歸方法都存在堆棧溢出的風險,此站點以以下名稱命名:)嘗試給ArrayList上萬個元素,看看會發生什么。

我建議您抽象地看一下這些算法的運行時間和空間復雜度(這些是效率的更多計算機科學名稱)。 這就是所謂的Big-Oh表示法

確切地說,當然,在使實現盡可能緊密和無副作用之后,您應該考慮編寫微基准測試。

由於您必須能夠讀取列表中每個元素的值以將這些元素加起來,因此沒有一種算法會比(線性) O(n)時間, O(1)空間算法(是在一般情況下 (即沒有任何其他假設)的迭代算法所執行的操作。 這里n是輸入的大小(即列表中元素的數量)。 這樣的算法被認為具有一個線性時間恆定的空間復雜性意味着其運行時間隨着列表中的尺寸增加,但它不需要任何附加的存儲器; 實際上,它需要一些恆定的內存來完成其工作。

由於迭代算法沒有遞歸算法所遇到的任何復雜性(例如,堆棧上的額外內存),因此其他兩種遞歸算法最多只能具有與這種簡單算法一樣好的性能。

這反映為具有相同O(f(n))運行時間的算法的常數項。 例如,如果您以某種方式找到了一種算法,該算法檢查列表中大約一半的元素以解決問題,而另一種算法必須查看所有元素,則第一種算法的常數項要比第二種更好,並且有望擊敗它實際上,盡管這兩種算法的時間復雜度均為O(n)

現在,很有可能通過將巨型列表拆分為較小的列表來並行化該問題的解決方案(您可以通過將索引分成單個列表來實現效果),然后使用並行求和操作,如果列表是足夠長。 這是因為每個非重疊間隔都可以並行(同時)求和,最后將部分和求和。 但這不是我們目前考慮的可能性。

我會說使用JavaGuava Google核心庫 例:

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

您可以使用所需的任何單位作為耗材,而且不需要任何額外的計算。

如果要考慮效率,那么您確實需要查看算法結構而不是時序。

加載正在使用的方法的源代碼,深入結構並尋找循環-這將為您提供正確的效率度量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM