将负整数解析为数组时程序出错

时间:2017-03-31 18:56:58

标签: java arrays parsing

我的任务中有一个奇怪的问题。我试图从用户输入中获取整数并将它们存储在一个数组中。之后,将对它们运行四个递归方法,以找到这些数字的不同特征。但是,每当我尝试在任何索引中使用负整数运行程序时,程序就会停止响应。

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);
            }
        }
    }

}

我相信这是解决问题所必需的唯一相关代码部分。如果需要额外的代码,请询问。谢谢!

2 个答案:

答案 0 :(得分:0)

替换你的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));
    }    
}

答案 1 :(得分:0)

您的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 octillion,9.5 x 10 ^ 29)。

您的程序不会因StackOverflowError而崩溃,因为堆栈深度在任何时候都不会超过数组的长度(加上主要的一个),但是它的生命周期将超过要运行的宇宙。

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个大小为100.事实上,你已经递归调用findMin来获取要比较的值,但随后调用它再次以获得相同的值返回应该是一个红旗。在许多情况下,这种不必要的重复只会是一个小麻烦;在这种情况下,这是灾难性的。

哦,我忘了提。输入否定号码的原因引发了这个问题:大概,你并不总是键入100个号码。我在尝试你的程序时从未这样做过。这太无聊了,你可以通过输入零来结束列表。分配数组时:

int[] numbers = new int[100];

数组填充零。因此,如果您输入十个数字,则数组的其余部分将为零,当我们在第一次调用findMin时到达此行时:

    if (findMin(numbers, startIndex, endIndex - 1) < numbers[endIndex])

最后的数字将为零,这也是最小值。所以我们只递归一次,而不是两次。对于大多数递归调用也会发生这种情况;它将发生在数组末尾的零尾长尾的所有那些。只有当我们进入用户实际输入值的条目时,我们才会看到双重递归行为。如果用户只输入大约10个号码,我们就是安全的。

但是,如果用户输入的是一个 否定 数字,那么这将成为最小值,而零则不会保护我们。我们在每次调用时都会遇到双递归,除了numbers[endIndex]持有该负数的那个。想想看,我得到2 ^(x-1)+ 2 ^(x-2) - 1而不是2 ^ x - 1的原因是因为我总是将负数放在 second < / em>数组中的位置。因此,根据最小值的位置,您可以获得比我上面描述的更好或更差的性能。