简体   繁体   English

如何避免java.lang.StackOverflowError:null?

[英]How can i avoid the java.lang.StackOverflowError:null?

I'm trying to learn Java a bit on my own and normally I have more then enough resources with good site's like these, but now I just want to know where I'm wrong. 我试图自己学习一点Java,通常我拥有更多的资源以及像这样的良好站点,但是现在我只想知道我错了。

So the problem was phrased as : 因此,问题表达为:

The following iterative sequence is defined for the set of positive integers: 为正整数的集合定义了以下迭代序列:

n → n/2 (n is even) n → 3n + 1 (n is odd) n→n / 2(n为偶数)n→3n +1(n为奇数)

Using the rule above and starting with 13, we generate the following sequence: 使用上面的规则并从13开始,我们生成以下序列:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. 13→40→20→10→5→16→8→4→2→1可以看出,该序列(从13开始并在1结束)包含10个项。 Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1. 尽管尚未证明(Collat​​z问题),但可以认为所有起始数字都以1结尾。

Which starting number, under one million, produces the longest chain? 最长的链条中小于100万的哪个起始数字?

NOTE: Once the chain starts the terms are allowed to go above one million. 注意:链条启动后,期限就可以超过一百万。

I keep getting these java.lang.StackOverflowError, could someone help me please. 我不断收到这些java.lang.StackOverflowError,有人可以帮我吗。 My code: 我的代码:

import java.util.HashMap;

public class Euler
{
    HashMap<Integer,Integer> check;
    int result;

    public Euler()
    {
        check = new HashMap<Integer,Integer>();     
    }

    public int search(int number)
    {

        int startingNumber = number;

        while (check.get(number)==null && number!=1){

            if (number%2==0){
                number = number / 2;
                result = search(number);
                result++;               
            }

            else {
                number = (3*number)+1;
                result = search(number);
                result++;
            }
        }

        if (check.get(startingNumber)!=null){
            result=result+check.get(number);
            check.put(startingNumber,result);

        }
        else{
            check.put(startingNumber,result);
        }

        return result;
    }

    public int test()
    {
        int temp = 0;
        int highest=0;
        int get = 0;
        for (int i=1000001;i>1;i--){
            result = 0;
            temp = search(i);
            if(temp>highest){
                highest=temp;
                get = i;
            }
            System.out.println(i);
        }

        return get;
    }


}

EDIT: 编辑:

public class Euler
{
   public Euler()
    {
    }

    public int quickSearch(int numb)
    {
        int steps = 0;
        while (numb != 1) {
            if (numb % 2 == 0) {
                numb /= 2;
            }
            else {
                numb = 3 * numb + 1;
            }
            steps++;
        }
        return steps;
    }


    public int test()
    {
        int temp = 0;
        int highest=0;
        int get = 0;
        for (int i=1;i<1000001;i=i+2){

            temp = quickSearch(i);
            if(temp>highest){
                highest=temp;
                get = i;
            }
            System.out.println(i);

        }

        return get;
    }
}

EDIT2: So in the EDIT version code, i got a freeze from the machine, but when i changed int to long, it worked perfectly, although I understand that with some Map to store values, you can find it faster. EDIT2:因此,在EDIT版本代码中,我从计算机中冻结,但是当我将int更改为long时,它可以正常工作,尽管我了解使用某些Map来存储值,您可以更快地找到它。 Thank you all !! 谢谢你们 !!

The problem is, that you have too many recursive calls. 问题是您有太多的递归调用。 The best resolution for this would be to make the code iterative. 最好的解决方案是使代码迭代。 Just rework your while loop to first check whether the number was found already if yes return the sum of the steps it took you to get to that number and it will take to get from that number to 1 . 只需重新整理while循环,首先检查是否已经找到该数字,如果是,则返回您获取该数字所用步骤的总和,该步骤将使该数字变为1 Otherwise just update the number for the next step, run through the loop again. 否则,只需更新下一步编号,然后再次运行循环即可。 Meanwhile, you just have to keep track of the steps it took you to get to a known number. 同时,您只需要跟踪获取已知号码所需的步骤。

Personally, I would remove the HashMap altogether and just have a simple while loop: 就个人而言,我将完全删除HashMap ,只是有一个简单的while循环:

int steps = 0;
while (number != 1) {
    if (number % 2 == 0) number /= 2;
    else number = 3 * number + 1
    steps++;
}

Edit: If you want to add a HashMap to store found values, you could do it like this (I assume you defined a HashMap<Long, Integer> named foundNumbers earlier): 编辑:如果您想添加一个HashMap来存储找到的值,则可以这样做(我假设您之前定义了一个名为foundNumbersHashMap<Long, Integer> ):

public int search(long number) {

    int steps = 0;
    long initialNumber = number;
    while (number != 1) {
        if (number % 2 == 0) number /= 2;
        else number = 3 * number + 1
        steps++;

        if (foundNumbers.containsKey(number)) {
            steps += foundNumbers.get(number)
            foundNumbers.put(initialNumber, steps);
            return steps;
        }
    }

    foundNumbers.put(initialNumber, steps);
    return steps;

}

Although recursion code is easy and compact in many cases but there is possibility of stack overflow, especially if the length of recursion chain is unknown. 尽管在许多情况下递归代码很容易且紧凑,但是存在堆栈溢出的可能性,尤其是在递归链的长度未知的情况下。

Your case is simple and can be easily tackled by iteration. 您的情况很简单,可以通过迭代轻松解决。 So, try using iterative model instead of recursive model. 因此,尝试使用迭代模型而不是递归模型。

The problem is here: 问题在这里:

public int search(int number)
{

    int startingNumber = number;

    while (check.get(number)==null && number!=1){

        if (number%2==0){
            number = number / 2;
            result = search(number);
            result++;               
        }

        else {
            number = (3*number)+1;
            result = search(number);
            result++;
        }
    }

    if (check.get(startingNumber)!=null){
        result=result+check.get(number);
        check.put(startingNumber,result);

    }
    else{
        check.put(startingNumber,result);
    }

    return result;
}

You call search(int) recursively and it cause stacking. 您递归调用search(int),这会导致堆栈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM