[英]Error in program when parsing negative integers into an array
我的一項任務遇到一個奇怪的問題。 我試圖從用戶輸入中獲取整數並將其存儲在數組中。 之后,將對它們運行四種遞歸方法以找到這些數字的不同特征。 但是,每當我嘗試在任何索引中使用負整數運行程序時,程序都會停止響應。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Assignment9 {
public static void main(String[] args) throws IOException {
int index = 0;
int[] numbers;
numbers = new int[100];
InputStreamReader inRead = new InputStreamReader(System.in);
BufferedReader buffRead = new BufferedReader(inRead);
String line = buffRead.readLine();
try {
while (!line.equals("0") && index < 100) {
numbers[index] = Integer.parseInt(line);
index++;
line = buffRead.readLine();
}
} catch (IOException exception) {
System.out.println("Array index out of bound");
}
` int min = findMin(numbers, 0, numbers.length - 1);
int sumAtEven = computeSumAtEvenIndexes(numbers, 0, numbers.length - 1);
int divByThree = countDivisibleBy3(numbers, 0, numbers.length - 1);
System.out.println("The minimum number is " + min);
System.out.println("The sum of numbers at even indexes is " + sumAtEven);
System.out.println("The count of numbers that are divisible by 3 is " + divByThree);
System.out.println("The maximum number among numbers that are less than the first number is " + maxLessThanFirst);
}
public static int findMin(int[] numbers, int startIndex, int endIndex) {
if (startIndex == endIndex) {
return numbers[startIndex];
} else if (findMin(numbers, startIndex, endIndex - 1) < numbers[endIndex]) {
return findMin(numbers, startIndex, endIndex - 1);
} else {
return numbers[endIndex];
}
}
public static int computeSumAtEvenIndexes(int[] numbers, int startIndex, int endIndex) {
if (startIndex == endIndex) {
if (startIndex % 2 == 0) {
return numbers[startIndex];
} else return 0;
} else {
if (endIndex % 2 == 0) {
return computeSumAtEvenIndexes(numbers, startIndex, endIndex - 1) + numbers[endIndex];
} else {
return computeSumAtEvenIndexes(numbers, startIndex, endIndex - 1);
}
}
}
public static int countDivisibleBy3(int[] numbers, int startIndex, int endIndex) {
if (startIndex == endIndex) {
if (numbers[startIndex] % 3 == 0) {
return 1;
} else {
return 0;
}
} else {
if (numbers[endIndex] == 0) {
return countDivisibleBy3(numbers, startIndex, endIndex - 1);
}
if (numbers[endIndex] % 3 == 0) {
return countDivisibleBy3(numbers, startIndex, endIndex - 1) + 1;
} else {
return countDivisibleBy3(numbers, startIndex, endIndex - 1);
}
}
}
}
我相信,這是理解該問題所必需的唯一相關代碼部分。 如果需要其他代碼,只需詢問。 謝謝!
替換您的findMin方法。 傳遞數組,索引為零;
public static int findMin(int[] numbers, int index) {
if (index == numbers.length - 1)
{
return numbers[index];
}
else
{
return Math.min(numbers[index], findMin(numbers, index + 1));
}
}
您的findMin
方法是雙重遞歸的:
public static int findMin(int[] numbers, int startIndex, int endIndex) {
if (startIndex == endIndex) {
return numbers[startIndex];
// in the next line, we recurse looking for the minimum
} else if (findMin(numbers, startIndex, endIndex - 1) < numbers[endIndex]) {
// we've found the minimum, but now we must recurse again to get it!
return findMin(numbers, startIndex, endIndex - 1);
} else {
return numbers[endIndex];
}
}
這將本來應該是線性算法的算法轉換為指數算法。 如果每次輸入findMin
都進行記錄,則會發現它隨着數組的大小而迅速增加。 實驗表明,它被稱為2 ^(x-1)+ 2 ^(x-2)-1次,其中x是數組的長度。
因此,如果您有一個大小為10的數組,它將被稱為767次。 對於大小為20的數組,它將被稱為786,431次。 大小30,25,165,823倍。 100號產量:
950,737,950,171,172,051,122,527,404,031調用(950八十進制,9.5 x 10 ^ 29)。
您的程序不會因StackOverflowError崩潰而崩潰,因為堆棧深度絕不會超過數組的長度(主數組加一個),但是運行所需的時間要比Universe的壽命長。
將findMin
更改為此:
public static int findMin(int[] numbers, int startIndex, int endIndex) {
if (startIndex == endIndex) {
return numbers[startIndex];
}
// there's no need for an else since the if ended with a return
int r = findMin(numbers, startIndex, endIndex - 1); // only recurse once
if (r < numbers[endIndex]) {
// we've found the minimum, return it without recursing again
return r;
}
// again, no need for else, here
return numbers[endIndex];
}
現在,該算法僅對大小為20的數組進行20次調用,對大小為50的數組進行50次調用,對大小為100的數組進行50次調用。您已經遞歸調用findMin
以獲取要比較的值,然后又再次調用它以獲取相同的值返回應該是一個危險信號。 在許多情況下,這種不必要的重復只會是一個小麻煩。 在這種情況下,這是災難性的。
哦,我忘了提。 輸入負數的原因觸發了該問題:大概您輸入的數字並不總是100。在嘗試程序時,我從未輸入過。 太無聊了,您可以通過輸入零來結束列表。 分配數組時:
int[] numbers = new int[100];
數組用零填充。 因此,如果輸入十個數字,則數組的其余部分將為零,並且在我們第一次調用findMin
時到達此findMin
:
if (findMin(numbers, startIndex, endIndex - 1) < numbers[endIndex])
最后的數字將為零,這也是最小值。 因此,我們僅遞歸一次,而不是兩次。 大多數遞歸調用也會發生這種情況。 數組末尾所有長為零的位都將發生這種情況。 只有當我們進入用戶實際輸入的值的條目時,我們才會看到雙遞歸行為。 如果用戶僅輸入大約10個數字,那么我們是安全的。
但是,如果用戶甚至輸入一個負數 ,那將成為最小值,並且零不會保護我們。 除了numbers[endIndex]
保留該負數的那個,我們在每次調用中都達到了雙重遞歸。 想一想,之所以得到2 ^(x-1)+ 2 ^(x-2)-1而不是2 ^ x-1是因為我總是將負數放在數組的第二個位置。 因此,根據最小值的不同,您可能會獲得比我上面描述的更好或更差的性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.