簡體   English   中英

Java中帶有查找表的程序階乘

[英]Program Factorial in Java with a lookup table

為了改進我的編程,我正在嘗試使用Java解決此問題。 我到處尋找一種優雅的解決方案,卻找不到。

編寫一個僅包含一個參數,計算階乘並在屏幕上顯示值的程序,該程序還必須是交互式的,而不是在每次計算后都終止,並且該程序使用以前的值表來提高性能。

我如何使它在方法調用中檢查是否已經計算出值的階乘? 還希望對此代碼進行任何其他改進以使其更具可讀性或效率。

這是我到目前為止所寫的。

public static void main(String[] args) {
    int input = 0;
    Scanner reader = new Scanner(System.in);

    HashMap cache = new HashMap();

    while(1 == 1){
        do{
            try {
                System.out.println("Enter the number you would like to factor");
                input = reader.nextInt();
            } catch (InputMismatchException e){
                reader.next();
            }
        } while(input <= 0);

        if(cache.get(input) != null){
            System.out.println("Found in cache");
            System.out.println(input + "! = " + cache.get(input));
        } 
        else {
            cache.put(input, factorialRecursively(input));
            System.out.println(input + "! = " + factorialRecursively(input));
        }

    }   

}       

public static int factorialIteratively(int a) throws InputMismatchException {
    int temp = 1;
    while(a > 0){
        temp = temp * a;
        a--;
    }
    return temp;
}

public static int factorialRecursively(int a) throws InputMismatchException{
    if (a == 1){
        return 1;
    }
    else {
        return a * factorialRecursively(a-1);
    }
}

好吧,我會試一下。 首先讓我給您完整的代碼答案,然后詳細介紹每次更改:

public static void main(String[] args) {
    int input = 0;

    try (Scanner reader = new Scanner(System.in)) {

        Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
        cache.put(1, 1);

        while (true) {
            do {
                try {
                    System.out.println("Enter the number you would like to factor");
                    input = reader.nextInt();
                } catch (InputMismatchException e){
                    reader.next();
                    input = 0;
                }
            } while(input <= 0);

            if(cache.get(input) != null) {
                System.out.println("Found in cache");
                System.out.println(input + "! = " + cache.get(input));
            } 
            else {
                int result = factorialRecursively(input, cache);
                System.out.println(input + "! = " + result);
            }
        }   
    }
}       

public static int factorialRecursively(int limit, Map<Integer, Integer> cache) {

    int cacheSize = cache.size();
    if (cacheSize < limit) {
        int nextFactorial = cacheSize + 1; 
        System.out.println("Calculating and caching " + nextFactorial + "!");
        cache.put(nextFactorial, cache.get(cacheSize) * nextFactorial); 
        return factorialRecursively(limit, cache);
    }
    else {
        return cache.get(limit);
    }
}

1)您問題的直接答案:“如何確保計算階乘的方法,檢查它是否已經為值計算了階乘”。 所以我堅持使用遞歸方法,盡管您也可以使用相同的概念來實現迭代版本。
基本上,這個想法是將結果緩存的引用傳遞給方法本身( Map<Integer, Integer> cache參數),因此它負責在每個乘法步驟中存儲結果計算的階乘,而不僅是一次完整的階乘已被計算。 為此,我使該方法從下至上而不是從反方向開始計算階乘。 我們將最小的階乘存儲在緩存中作為起點( cache.put(1, 1); )。 我添加了一條輸出消息,顯示了何時計算和緩存階乘,並且通過測試代碼,您可以看到一個特定階乘僅被計算和存儲一次。

2)使用Map<Integer, Integer> cache = new HashMap<Integer, Integer>(); 而不是HashMap cache = new HashMap();
a)從Java 1.5開始,集合已經變得通用(長話短說,超出了此處的范圍),並且在引用時應進行參數化。 因此,這里我們要說的是,我想存儲整數值(計算的階乘),以便可以使用整數鍵(階乘源)進行訪問。
b)代碼之所以可以編譯並允許我們使用整數基元而不是Integer類對象,是因為有一種名為自動裝箱的機制,該機制將整數基元無縫地包裝到Integer對象中,反之亦然。 同樣,超出范圍,但是應該意識到這一點。
c)我們這里要使用的功能是Map接口的功能, HashMap恰好是該接口的實現。 除非引用代碼(不太可能)依賴於HashMap特定的方法,否則,將變量聲明為相應的集合接口(如ArrayList List等)而不是實現類是一個好習慣。

3)InputMismatchException僅由Scanner類引發,因此不需要由任何未調用Scanner nextInt()方法的代碼引發。

4)使用true代替1 == 1 在實踐中等效,但是使用布爾值更具可讀性。

5)僅調用一次factorialRecursively方法。 您的代碼兩次調用該方法,這是不必要的。 如果您追求效率和優雅,則只應調用該方法一次並將其結果存儲在變量中。

6)使用try (Scanner reader = new Scanner(System.in)) { ...代替Scanner reader = new Scanner(System.in); Scanner對象必須始終調用其close()方法來清理資源。 在較早的Java版本中,這是通過try {} finally {}語句實現的,但是,如果該類實現了AutoCloseable接口,則更高的版本允許使用這種語法(try-with-resources語句)。 這意味着可以確保始終調用close()方法。

7)最后但並非最不重要的一點:我沒有改變過intInteger的使用。 如@indivisible在注釋中所建議,您應該了解數據類型限制 一個int只能保存由31位+符號(-2 ^ 31 -1到2 ^ 31)表示的數字,這會將代碼限制為16 !,之后結果將是錯誤的。 如果希望生成更大的數字,則應使用long / Long 無論如何,確實再次超出了這個問題的范圍。

玩得開心 :)

暫無
暫無

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

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