Как избежать StackOverflowError для рекурсивной функции

Я пишу функцию, которая будет вызывать сама себя до 5000 раз. Конечно, я получаю StackOverflowError. Есть ли способ, которым я могу переписать этот код довольно простым способом?:

void checkBlocks(Block b, int amm) {

    //Stuff that might issue a return call

    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition) 
        checkBlocks(blockDown, amm);


    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
        checkBlocks(blockUp, amm);

    //Same code 4 more times for each side

}

кстати, каково ограничение того, насколько глубоко мы можем называть функции?

6 ответов


используйте явный стек объектов и цикл, а не стек вызовов и рекурсию:

void checkBlocks(Block b, int amm) {
  Stack<Block> blocks = new Stack<Block>();
  blocks.push(b);
  while (!blocks.isEmpty()) {
    b = blocks.pop();
    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition)
      blocks.push(block);
    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
      blocks.push(block);
  }
}

размер стека по умолчанию в java - 512kb. если вы превысите, что программа прекратит бросать StackOverflowException

вы можете увеличить размер стека, передав аргумент JVM : - Xss1024k

теперь размер стека 1024kb. вы можете дать более высокое значение на основе вашей среды

Я не думаю, что мы можем программно изменить этот


вы можете увеличить размер стека с помощью -Xss4m.


вы можете поместить свой "блок" в очередь / стек и повторять, пока блоки доступны.


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

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


в большинстве случаев рекурсия используется неправильно. Вы не должны получать stack over flow exception. Ваш метод не имеет возвращаемого типа / значения. Как вы гарантируете, что ваш начальный блок b действителен?

Если вы используете рекурсию, ответьте себе на следующий вопрос:

  • каков мой якорь рекурсии (когда я останавливаюсь на рекурсии)
  • каков мой шаг рекурсии (как уменьшить количество расчеты)

пример:

  • n! => n*n-1!

мой якорь рекурсии n == 2 (результат 2), поэтому я могу вычислить все результаты, начинающиеся с этого якоря.

Мой шаг рекурсии-n-1 (поэтому с каждым шагом я приближаюсь к решению (и в этом факте к моему якорю рекурсии))