[英]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)最后但並非最不重要的一點:我沒有改變過int
和Integer
的使用。 如@indivisible在注釋中所建議,您應該了解數據類型限制 。 一個int
只能保存由31位+符號(-2 ^ 31 -1到2 ^ 31)表示的數字,這會將代碼限制為16 !,之后結果將是錯誤的。 如果希望生成更大的數字,則應使用long
/ Long
。 無論如何,確實再次超出了這個問題的范圍。
玩得開心 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.