簡體   English   中英

將負整數解析為數組時程序錯誤

[英]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.

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