Как я могу избежать ошибки java.lang.StackOverflowError: null?

Я пытаюсь немного изучить Java самостоятельно, и обычно у меня более чем достаточно ресурсов с такими хорошими сайтами, как этот, но теперь я просто хочу знать, в чем я ошибаюсь.

Итак, проблема была сформулирована так:

Следующая итерационная последовательность определена для набора натуральных чисел:

n → n / 2 (n четно) n → 3n + 1 (n нечетно)

Используя приведенное выше правило и начиная с 13, мы генерируем следующую последовательность:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1. Видно, что эта последовательность (начиная с 13 и заканчивая 1) содержит 10 членов. Хотя это еще не доказано (задача Коллатца), считается, что все стартовые номера заканчиваются на 1.

Какое начальное число меньше миллиона дает самую длинную цепочку?

ПРИМЕЧАНИЕ. После запуска цепочки разрешено превышать один миллион терминов.

Я продолжаю получать эти java.lang.StackOverflowError, может кто-нибудь мне помочь. Мой код:

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


}

РЕДАКТИРОВАТЬ:

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: Итак, в коде версии EDIT у меня завис компьютер, но когда я изменил int на long, он работал отлично, хотя я понимаю, что с некоторой картой для хранения значений вы можете найти его быстрее. Спасибо вам всем !!


person Robert    schedule 28.09.2016    source источник
comment
Я пытаюсь изучить javascript - Java и JavaScript - это разные языки. Ваш код - Java   -  person JonK    schedule 28.09.2016
comment
Почему вы используете хэш-карту для хранения результата и начального номера этого результата? Поиск материала из хэш-карты, вероятно, медленнее, чем умножение его на 3 и добавление 1 или деление на 2   -  person Bálint    schedule 28.09.2016
comment
@JonK Не забудьте указать ссылку в javascriptisnotjava.io   -  person Bálint    schedule 28.09.2016
comment
@ Bálint Я сохраняю его в хэш-карте, поэтому, когда я уже встречаю число, которое уже было обработано, я беру значение, добавляю плюс 1 и сохраняю его тоже. Или это глупо?   -  person Robert    schedule 28.09.2016
comment
Чтобы узнать, воспользуйтесь отладчиком. Подсказка: вы повторяетесь без условия завершения. Ваша карта никогда не обновляется, потому что вы бесконечно повторяете рекурсию перед обновлением карты.   -  person Erwin Bolwidt    schedule 28.09.2016
comment
@Robert снова, поиск вещей по хэш-карте, вероятно, медленнее, чем фактический алгоритм   -  person Bálint    schedule 28.09.2016
comment
В чем проблема модифицированного итеративного кода?   -  person Amber Beriwal    schedule 28.09.2016


Ответы (3)


Проблема в том, что у вас слишком много рекурсивных вызовов. Лучшее решение для этого - сделать код итеративным. Просто переработайте цикл while, чтобы сначала проверить, был ли уже найден номер, если да, верните сумму шагов, которые потребовались вам, чтобы добраться до этого числа, и которое потребуется, чтобы перейти от этого числа к 1. В противном случае просто обновите номер для следующего шага, снова выполните цикл. Между тем, вам просто нужно отслеживать шаги, которые вам потребовались, чтобы добраться до известного числа.

Лично я бы вообще удалил HashMap и оставил бы простой while цикл:

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

Изменить: если вы хотите добавить HashMap для хранения найденных значений, вы можете сделать это следующим образом (я предполагаю, что ранее вы определили HashMap<Long, Integer> с именем foundNumbers):

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;

}
person Leon    schedule 28.09.2016
comment
так ты имеешь в виду как код в РЕДАКТИРОВАТЬ? но потом он останавливается на 113381 и не двигается ... - person Robert; 28.09.2016
comment
Я нашел этот вопрос и, похоже, то же упражнение. Глядя в комментарии, кажется, что int слишком мало для ваших цифр. Может попробовать long. Кроме того, если это занимает слишком много времени, вы можете попытаться добавить HashMap для сохранения найденных значений (как вы уже делали в исходном коде, только с итерацией вместо рекурсии), чтобы сократить необходимое время. - person Leon; 28.09.2016

Хотя код рекурсии во многих случаях прост и компактен, но существует вероятность переполнения стека, особенно если длина цепочки рекурсии неизвестна.

Ваш случай прост и может быть легко решен путем повторения. Итак, попробуйте использовать итеративную модель вместо рекурсивной модели.

person Amber Beriwal    schedule 28.09.2016
comment
если вы используете итерацию, вы не делаете какие-то вычисления вдвое? Если вы возьмете число 3, это: 3 10 5 16 8 4 2 1, и когда вы позже возьмете число 10, он сделает все вычисления, а если я использую рекурсию, числа 10,5,16,8 , 4,2 сохраняются сразу, так что когда вы дойдете до 10, ему больше не придется вычислять? - person Robert; 28.09.2016
comment
Вы также можете управлять этим в цикле, используя HashMap, так же, как вы поддерживаете его в рекурсии. - person Amber Beriwal; 28.09.2016

Проблема здесь:

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

Вы рекурсивно вызываете search (int), и это вызывает наложение.

person Shaq    schedule 28.09.2016
comment
если (число% 2 == 0) {число = число / 2; результат = поиск (число); результат ++; } else {число = (3 * число) +1; результат = поиск (число); результат ++; } - person Shaq; 28.09.2016
comment
Возможно, проблема здесь;) stackoverflow.com/questions/214741/what -is-a-stackoverflowerror - person Shaq; 28.09.2016