Think of a for loop as a little anonymous function that takes the loop index value as a parameter. In order to start the next iteration of the loop, the function can return a call to itself with a new value for the loop index parameter.
Like this:
Object loop(int i, Object data) {
if (i > 0) {
return loop(i - 1, evolve(data));
} else {
return data;
}
}
That's the same as this:
for ( ; i > 0; i--) {
data = evolve(data);
}
In some languages, particularly Scheme, and who knows maybe Java 8 or 9, the compiler is guaranteed to compile a recursive function such as the function loop above just the same as it compiles the for loop above.
In other languages, including the current and past versions of Java, nearly all compilers will make an executable that builds a big call stack. When the call stack is large it may even overflow the permitted size and crash the program.
Answer from minopret on Stack OverflowThink of a for loop as a little anonymous function that takes the loop index value as a parameter. In order to start the next iteration of the loop, the function can return a call to itself with a new value for the loop index parameter.
Like this:
Object loop(int i, Object data) {
if (i > 0) {
return loop(i - 1, evolve(data));
} else {
return data;
}
}
That's the same as this:
for ( ; i > 0; i--) {
data = evolve(data);
}
In some languages, particularly Scheme, and who knows maybe Java 8 or 9, the compiler is guaranteed to compile a recursive function such as the function loop above just the same as it compiles the for loop above.
In other languages, including the current and past versions of Java, nearly all compilers will make an executable that builds a big call stack. When the call stack is large it may even overflow the permitted size and crash the program.
Haters aside, let's do this! [1]
Given:
int x = 3;
for (int i = 0; i < x; i++) {
for (int j = 0; j < x; j++) {
for (int k = 0; k < x; k++){
list.add(array[i] + array[j] + array[k]);
}
}
}
Let's consider that each loop is it's own recursive function - as this makes the recurrence cases much easier! This is also the only "non-thinking" method I know of to turn the loops into recursion. The recursive depth will be limited to 3*x => i+j+k so it's "fairly safe" for a smallish[2] x.
In Java it requires a separate method for each loop to encode this structure. (In a language with higher-order functions these three functions might be abstractly combined .. but not in Java [7].)
void loopI(int i) {
if (i < x) {
loopJ(0); // "start j loop"
loopI(i++); // "next i loop" / recurrence case
}
// "end loop" / base case
}
void loopJ(int j) {
if (j < x) {
loopK(0);
loopJ(j++);
}
}
void loopK(int k) {
if (k < x) {
list.add(array[i] + array[j] + array[k]);
loopK(k++);
}
}
// do it!
loopI(0);
All of these could be combined into a single recursive function, but that makes handling the recurrence cases a bit tougher as "thinking" and additional conditionals (or mod expressions, perhaps) are required to advance the state.
Here is an example of a combined recursive function (this is incorrect when x is 0). Unlike the three method approach above, the stack depth will grow to x^3 => i*j*k. This will easily kill Java's recursion limits - even for smallish values of x- as Java [7] doesn't have tail-call optimization.
void loop(int i, int j, int k) {
list.add(array[i] + array[j] + array[k]);
// advance states
k++;
if (k == x) { k = 0; j++; }
if (j == x) { j = 0; i++; }
if (i == x) { i = 0; }
// terminate on all wrap-around
if (i == 0 && j == 0 && k == 0) { return; }
// recurse
loop(i, j, k);
}
[1] YMMV, for theoretical purposes only - I love recursion, but it's not suited for this case in Java.
[2] For some value of "smallish". See how deep your stack can go!
Videos
Actually you should break the function down first:
A loop has a few parts:
the header, and processing before the loop. May declare some new variables
the condition, when to stop the loop.
the actual loop body. It changes some of the header's variables and/or the parameters passed in.
the tail; what happens after the loop and return result.
Or to write it out:
foo_iterative(params){
header
while(condition){
loop_body
}
return tail
}
Using these blocks to make a recursive call is pretty straightforward:
foo_recursive(params){
header
return foo_recursion(params, header_vars)
}
foo_recursion(params, header_vars){
if(!condition){
return tail
}
loop_body
return foo_recursion(params, modified_header_vars)
}
Et voilΓ ; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.
Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.
We can use a switch to work around that:
bar_recurse(params){
if(baseCase){
finalize
return
}
body1
bar_recurse(mod_params)
body2
bar_recurse(mod_params)
body3
}
bar_iterative(params){
stack.push({init, params})
while(!stack.empty){
stackFrame = stack.pop()
switch(stackFrame.resumPoint){
case init:
if(baseCase){
finalize
break;
}
body1
stack.push({resum1, params, variables})
stack.push({init, modified_params})
break;
case resum1:
body2
stack.push({resum2, params, variables})
stack.push({init, modified_params})
break;
case resum2:
body3
break;
}
}
}
Following up on @ratchet freak's answer, I created this example of how the Fibonacci function can be rewritten to a while loop in Java. Note that There's a much simpler (and efficient) way to rewrite the Fibonacci with a while loop though.
class CallContext { //this class is similar to the stack frame
Object[] args;
List<Object> vars = new LinkedList<>();
int resumePoint = 0;
public CallContext(Object[] args) {
this.args = args;
}
}
static int fibonacci(int fibNumber) {
Deque<CallContext> callStack = new LinkedList<>();
callStack.add(new CallContext(new Object[]{fibNumber}));
Object lastReturn = null; //value of last object returned (when stack frame was dropped)
while (!callStack.isEmpty()) {
CallContext callContext = callStack.peekLast();
Object[] args = callContext.args;
//actual logic starts here
int arg = (int) args[0];
if (arg == 0 || arg == 1) {
lastReturn = arg;
callStack.removeLast();
} else {
switch (callContext.resumePoint) {
case 0: //calculate fib(n-1)
callStack.add(new CallContext(new Object[]{arg - 1}));
callContext.resumePoint++;
break;
case 1: //calculate fib(n-2)
callContext.vars.add(lastReturn); //fib1
callStack.add(new CallContext(new Object[]{arg - 2}));
callContext.resumePoint++;
break;
case 2: // fib(n-1) + fib(n-2)
callContext.vars.add(lastReturn); //fib2
lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
callStack.removeLast();
break;
}
}
}
return (int) lastReturn;
}
Like so:
public class Recursive {
public void r(int i) {
if (i < 1024) {
i *= 2;
System.out.println("Count is: " + i);
r(i);
}
}
public static void main(String[] args) {
Recursive r = new Recursive();
r.r(1);
}
}
Take the loop of main and put it in its own function with an argument int i. In that function, rewrite the loop to
- If the loop condition is false (
i >= 1024), thenreturn - Else, recursive call with argument
i*2.
Call the function with argument 1 or 2, depending on which of your programs you're rewriting (they don't entirely match).
You misunderstood recursion: although it can be used to replace iteration, there is absolutely no requirement for the recursive function not to have iterations internal to itself.
The only requirement for a function to be considered recursive is the existence of a code path through which it calls itself, directly or indirectly. All correct recursive functions also have a conditional of some sort, preventing them from "recursing down" forever.
Your recursive function is ideal to illustrate the structure of recursive search with backtracking. It starts with the check of the exit condition row < n, and proceeds to making search decisions on its level of recursion (i.e. picking a possible position for queen number row). After each iteration, a recursive call is made to build upon the configuration that the function has found so far; eventually, it "bottoms out" when row reaches n in the recursive call that is n levels deep.
The general structure of a recursive function is something like this:
myRecursiveFunction(inputValue)
begin
if evaluateBaseCaseCondition(inputValue)=true then
return baseCaseValue;
else
/*
Recursive processing
*/
recursiveResult = myRecursiveFunction(nextRecursiveValue); //nextRecursiveValue could be as simple as inputValue-1
return recursiveResult;
end if
end
The text that I marked as /*recursive processing*/ could be anything. It could include a loop, if the problem being solved requires it, and could also include recursive calls to myRecursiveFunction.
To answer your original question: the code continues because the labeled break doesn't "transfer control flow" to the label, but to the statement just following the labeled statement. Let me illustrate with a tree (my ASCII art isn't great, but bear with me..)
- Item1
+- Subitem1
+- Sub1Subitem1
+- Sub1Subitem2 >==|
+- Sub1Subitem3 | break outer;
+- Subitem2 <=======|
+- Sub2Subitem1
...
- Item N
Now, if you do your break on, say, Sub1Subitem2, you break out of walking that collection of child nodes (Sub1Subitem#), popping you back out a SINGLE level, which should mean you'll end up at SubItem2, bypassing Sub1Subitem3 because you broke out the one level, but still running because you've recursed MORE than one level.
If you are trying to break completely out of the cycle (meaning if you find the answer in Sub1Subitem2, as per the example, you are done and need do no more) you'll need to break out of ALL levels, not just one. This other StackOverflow answer has a suggestion for doing just that.
1) The simple solution:
for (int i = 0; i < list.getLength() && !isFound; i++) {
2) Another, better solution would be not to use "break". Just modify the method from "void" to "boolean", return the boolean result, and don't use global variable "isFound".
Your problem is not in the part you posted.
I added dummy implementations for all the classes and methods used in your method, and it runs quite fine, stopping at level 6.
package de.fencing_game.paul.examples;
import java.util.*;
public class RecursionAndLoop {
private static class Move {
private String id;
public Move(String type) {
this.id = type;
}
public String toString(){
return "Move(" + id + ")";
}
}
private static class GameState {
private static int nextID;
private int id;
GameState() {
this.id = nextID++;
}
public GameState getNewInstance(Move move) {
return new GameState();
}
public int getPossibleMoveCount(int index) {
return 5;
}
public Vector<Move> getPossibleMoves(int index) {
Vector<Move> v = new Vector<Move>();
for(int i = 0; i < 5; i++) {
v.add(new Move(index + "Γ" + i));
}
return v;
}
public int getMarkCount(int index) {
return 20 + index;
}
public String toString() {
return "GameState[" + id + "]";
}
}
private static class Node {
private GameState state;
private Move move;
private List<Node> children;
private Node parent;
private int score;
public Node(GameState s, Move m) {
this.children = new ArrayList<Node>();
this.state = s;
this.move = m;
}
public void addChild(Node child) {
children.add(child);
}
public void setParent(Node node) {
parent = node;
}
public void setScore(int neu) {
this.score = neu;
}
public int getDepth() {
if(parent == null) {
return 0;
}
return 1 + parent.getDepth();
}
/**
* prints a simple tree view of this ZipNode and its descendants
* on {@link System.out}.
* @param prefix a prefix string to add before all lines.
* @param self a prefix string to add before the line of this node
* itself (after the general prefix).
* @param sub a prefix string to add before the line of all subnodes
* of this node (after the general prefix).
*/
private void printTree(String prefix,
String self,
String sub) {
System.out.println(prefix + self + state + " - " + move +
" - " + score);
String subPrefix = prefix + sub;
// the prefix strings for the next level.
String nextSelf = " ββ ";
String nextSub = " β ";
Iterator<Node> iterator =
this.children.iterator();
while(iterator.hasNext()) {
Node child = iterator.next();
if(!iterator.hasNext() ) {
// last item, without the "|"
nextSelf = " ββ ";
nextSub = " ";
}
child.printTree(subPrefix, nextSelf, nextSub);
}
}
}
int switchIndex(int index) {
return index + 1;
}
private void makeTree(GameState prevState, Vector<Move> moves, Node parentNode, int index, int depthLimit) {
if(prevState.getPossibleMoveCount(index) != 0){
for(int i = 0; i < moves.size(); i++){
Move thisMove = moves.get(i);
GameState newState = prevState.getNewInstance(thisMove);
Node child = new Node(newState, thisMove);
parentNode.addChild(child);
child.setParent(parentNode);
if((child.getDepth() + 1) < depthLimit){
int newIndex = switchIndex(index);
Vector<Move> newMoves = newState.getPossibleMoves(newIndex);
makeTree(newState, newMoves, child, newIndex, depthLimit);
}else{
child.setScore(newState.getMarkCount(index));
}
}
}
}
public static void main(String[] params) {
GameState start = new GameState();
Vector<Move> m = new Vector<Move>();
m.add(new Move("start"));
Node root = new Node(start, null);
int index = 7;
int depthLimit = 6;
new RecursionAndLoop().makeTree(start, m, root, index, depthLimit);
root.printTree("", " ", "");
}
}
(I changed a bit to generic types to avoid compiler warnings.)
Here is the output for depthLimit=4:
GameState[0] - null - 0
ββ GameState[1] - Move(start) - 0
ββ GameState[2] - Move(8Γ0) - 0
β ββ GameState[3] - Move(9Γ0) - 29
β ββ GameState[4] - Move(9Γ1) - 29
β ββ GameState[5] - Move(9Γ2) - 29
β ββ GameState[6] - Move(9Γ3) - 29
β ββ GameState[7] - Move(9Γ4) - 29
ββ GameState[8] - Move(8Γ1) - 0
β ββ GameState[9] - Move(9Γ0) - 29
β ββ GameState[10] - Move(9Γ1) - 29
β ββ GameState[11] - Move(9Γ2) - 29
β ββ GameState[12] - Move(9Γ3) - 29
β ββ GameState[13] - Move(9Γ4) - 29
ββ GameState[14] - Move(8Γ2) - 0
β ββ GameState[15] - Move(9Γ0) - 29
β ββ GameState[16] - Move(9Γ1) - 29
β ββ GameState[17] - Move(9Γ2) - 29
β ββ GameState[18] - Move(9Γ3) - 29
β ββ GameState[19] - Move(9Γ4) - 29
ββ GameState[20] - Move(8Γ3) - 0
β ββ GameState[21] - Move(9Γ0) - 29
β ββ GameState[22] - Move(9Γ1) - 29
β ββ GameState[23] - Move(9Γ2) - 29
β ββ GameState[24] - Move(9Γ3) - 29
β ββ GameState[25] - Move(9Γ4) - 29
ββ GameState[26] - Move(8Γ4) - 0
ββ GameState[27] - Move(9Γ0) - 29
ββ GameState[28] - Move(9Γ1) - 29
ββ GameState[29] - Move(9Γ2) - 29
ββ GameState[30] - Move(9Γ3) - 29
ββ GameState[31] - Move(9Γ4) - 29
When you call
makeTree(newState, newMoves, child, newIndex, depth);
inside of your if statement where are you expecting depth to come from? It looks like you're passing in depth to the makeTree routine, yet expecting it to be the depth of the current node (this.depth maybe?)