Думая о вещах, которые действительно нуждаются в стеке:
Если мы рассмотрим шаблон рекурсии как:
if(task can be done directly) {
return result of doing task directly
} else {
split task into two or more parts
solve for each part (possibly by recursing)
return result constructed by combining these solutions
}
Например, классическая Ханойская башня
if(the number of discs to move is 1) {
just move it
} else {
move n-1 discs to the spare peg
move the remaining disc to the target peg
move n-1 discs from the spare peg to the target peg, using the current peg as a spare
}
Это можно перевести в цикл, работающий с явным стеком, переставив его как:
place seed task on stack
while stack is not empty
take a task off the stack
if(task can be done directly) {
Do it
} else {
Split task into two or more parts
Place task to consolidate results on stack
Place each task on stack
}
}
Для Ханойской башни это становится:
stack.push(new Task(size, from, to, spare));
while(! stack.isEmpty()) {
task = stack.pop();
if(task.size() = 1) {
just move it
} else {
stack.push(new Task(task.size() -1, task.spare(), task,to(), task,from()));
stack.push(new Task(1, task.from(), task.to(), task.spare()));
stack.push(new Task(task.size() -1, task.from(), task.spare(), task.to()));
}
}
Здесь существует значительная гибкость в отношении того, как вы определяете свой стек. Вы можете сделать свой стек списком Command
объектов, которые делают сложные вещи. Или вы можете пойти в противоположном направлении и составить список простых типов (например, «задание» может быть 4 элемента в стеке int
, а не один элемент в стеке Task
).
Все это означает, что память для стека находится в куче, а не в стеке выполнения Java, но это может быть полезно, поскольку у вас больше контроля над ней.