Principle 12.6.1. EFFECTIVE DESIGN: Tail Recursion.
Tail-recursive algorithms are relatively simple to convert into iterative algorithms that do the same thing.
drawBoxes()
method into an iterative version:private void drawBoxesIterative(Graphics g, int level, int locX, int locY, int side, int delta) {
for (int k = level; k >= 0; k--) {
g.drawRect(locX, locY, side, side); // Draw a square
locX += delta; // Calculate new location
locY += delta;
side -= 2 * delta; // Calculate new side length
}
} // drawBoxesIterative()
private void drawBoxes(Graphics g, int level, int locX, int locY, int side, int delta) {
g.drawRect(locX, locY, side, side);
if (level > 0) {
int newLocX = locX + delta;
int newLocY = locY + delta;
drawBoxes(g, level - 1, newLocX, newLocY, side - 2 * delta, delta);
} // if
} // drawBoxes()
drawGasket()
method. It is clearly a case where the recursive approach makes the problem easier to solve.drawBoxes()
and drawGasket()
is that drawBoxes()
is an example of a tail-recursive method. A method is tail recursive if all of its recursive calls occur as the last action performed in the method. You have to be a bit careful about this definition. The recursive call in a tail-recursive method has to be the last executed statement. It needn’t be the last statement appearing in the method’s definition.public void printHello(int N) {
if (N > 1) {
System.out.println("Hello");
printHello(N - 1); // The last executed statement
} else
System.out.println("Hello");
} // printHello()
public void printHelloIterative(int N) {
for (int k = N; k > 0; k--)
System.out.println("Hello");
}
drawGasket()
and drawBoxes()
methods. Yet it is precisely for these nontail-recursive algorithms that recursion turns out to be most useful.for (int k = lev; k > 0; k--) {
drawGasket(g, lev - 1, p1X, p1Y, q1X, q1Y, q2X, q2Y);
drawGasket(g, lev - 1, p2X, p2Y, q1X, q1Y, q3X, q3Y);
drawGasket(g, lev - 1, p3X, p3Y, q2X, q2Y, q3X, q3Y);
}
printReverse()
tail recursive?
printReverse()
method is tail recursive.public void printReverse(String s) {
if (s.length() > 0) { // Recursive case:
printReverse(s.substring(1)); // Print tail
System.out.print(s.charAt(0)); // Print first char
}
} // printReverse()
countChar()
tail recursive?
countChar()
method is tail recursive.public int countChar(String s, char ch) {
if (s.length() == 0) // Base case: empty string
return 0;
else if (s.charAt(0) == ch) // Recursive case 1
return 1 + countChar(s.substring(1), ch); // Head = ch
else // Recursive case 2
return 0 + countChar(s.substring(1), ch); // Head != ch
} // countChar()