Big Java 6

Chapter 13 – Recursion

Chapter Goals

nested dolls showing recursiuon

Triangle Numbers

Outline of Triangle Class

public class Triangle 
{ 
   private int width;  
   
   public Triangle(int aWidth) 
   { 
      width = aWidth; 
   } 
   public int getArea() 
   { 
      . . . 
   } 
}

Handling Triangle of Width 1

Handling the General Case

Completed getArea Method

public int getArea() 
{ 
	if (width == 1) {
		return 1;
	} 
	Triangle smallerTriangle = new Triangle(width - 1); 
	int smallerArea = smallerTriangle.getArea(); 
	return smallerArea + width; 
}
A recursive computation solves a problem by using the solution to the same problem with simpler inputs.

Computing the area of a triangle with width 4

Recursion

Other Ways to Compute Triangle Numbers

section_1/Triangle.java

Your browser does not support the <object> tag.

section_1/TriangleTester.java

Your browser does not support the <object> tag. Program Run:

Self Check 13.1

Why is the statement else if (width == 1) { return 1; } in the getArea method unnecessary?

Self Check 13.2

How would you modify the program to recursively compute the area of a square?

Self Check 13.3

In some cultures, numbers containing the digit 8 are lucky numbers. What is wrong with the following method that tries to test whether a number is lucky?
public static boolean isLucky(int number)
{
   int lastDigit = number % 10;
   if (lastDigit == 8) { return true; }
   else
   {
      return isLucky(number / 10); // Test the number without the last digit
   }
}

Self Check 13.5

Consider the following recursive method:
public static int mystery(int n)
{
   if (n <= 0) { return 0; }
   else
   {
      int smaller = n - 1;
      return mystery(smaller) + n * n;
   }
}
What is mystery(4)?

Tracing Through Recursive Methods

debug a recursive method with a debugger

To debug recursive methods with a debugger, you need to be particularly careful, and watch the call stack to understand which nested call you currently are in.

Thinking Recursively

spiral

Thinking recursively is easy if you can recognize a subtask that is similar to the original task. 

Implement isPalindrome Method: How To 13.1

public class Sentence 
{ 
   private String text; 
   /** 
      Constructs a sentence. 
      @param aText a string containing all characters of the sentence 
   */ 
   public Sentence(String aText) 
   { 
       text = aText; 
   } 
   /** 
      Tests whether this sentence is a palindrome. 
      @return true if this sentence is a palindrome, false otherwise 
   */ 
   public boolean isPalindrome() 
   { 
      . . . 
   } 
}

Thinking Recursively: How To 13.1

1. Consider various ways to simplify inputs.
Here are several possibilities:

Thinking Recursively: How To 13.1

2. Combine solutions with simpler inputs into a solution of the original problem.

Thinking Recursively: How To 13.1

3. Find solutions to the simplest inputs.

Thinking Recursively: How To 13.1

4. Implement the solution by combining the simple cases and the reduction step:
public boolean isPalindrome() 
{ 
   int length = text.length(); 
   // Separate case for shortest strings. 
   if (length <= 1) { return true; } 
   // Get first and last characters, converted to lowercase. 
   char first = Character.toLowerCase(text.charAt(0)); 
   char last = Character.toLowerCase(text.charAt(length - 1)); 
   if (Character.isLetter(first) && Character.isLetter(last)) 
   { 
      // Both are letters. 
      if (first == last) 
      { 
         // Remove both first and last character. 
         Sentence shorter = new Sentence(text.substring(1, length - 1)); 
         return shorter.isPalindrome(); 
      } 
      else 
      { 
         return false;
      } 
   } 
   else if (!Character.isLetter(last)) 
   { 
      // Remove last character. 
      Sentence shorter = new Sentence(text.substring(0, length - 1)); 
      return shorter.isPalindrome(); 
   } 
   else 
   { 
      // Remove first character. 
      Sentence shorter = new Sentence(text.substring(1)); 
      return shorter.isPalindrome(); 
   } 
}

Recursive Helper Methods

cook

Recursive Helper Methods: isPalindrome

public boolean isPalindrome(int start, int end)
{
   // Separate case for substrings of length 0 and 1.
   if (start >= end) { return true; }
   // Get first and last characters, converted to lowercase. 
   char first = Character.toLowerCase(text.charAt(start)); 
   char last = Character.toLowerCase(text.charAt(end)); 
   if (Character.isLetter(first) && Character.isLetter(last)) 
   { 
      if (first == last) 
      { 
         // Test substring that doesn’t contain the matching letters. 
         return isPalindrome(start + 1, end - 1); 
      } 
      else 
      { 
         return false; 
      } 
   } 
   else if (!Character.isLetter(last)) 
   { 
      // Test substring that doesn’t contain the last character. 
      return isPalindrome(start, end - 1); 
   } 
   else 
   { 
      // Test substring that doesn’t contain the first character. 
      return isPalindrome(start + 1, end); 
   } 
}

Recursive Helper Methods

Self Check 13.6

Do we have to give the same name to both isPalindrome methods?

The Efficiency of Recursion: Fibonacci Sequence

section_3/RecursiveFib.java

Your browser does not support the <object> tag. Program Run:

The Efficiency of Recursion

section_3/RecursiveFibTracer.java

Your browser does not support the <object> tag. Program Run:

Call Tree for Computing fib(6)

fib calling tree

Figure 2 Call Pattern of the Recursive fib Method

The Efficiency of Recursion

section_3/LoopFib.java

Your browser does not support the <object> tag. Program Run:

The Efficiency of Recursion

lightbulbs

Iterative isPalindrome Method

public boolean isPalindrome() 
{ 
   int start = 0; 
   int end = text.length() - 1; 
   while (start < end) 
   { 
      char first = Character.toLowerCase(text.charAt(start)); 
      char last = Character.toLowerCase(text.charAt(end); 
      if (Character.isLetter(first) && Character.isLetter(last)) 
      { 
         // Both are letters. 
         if (first == last) 
         { 
            start++; 
            end--; 
         } 
         else 
         { 
            return false; 
         } 
      } 
      if (!Character.isLetter(last)) { end--; } 
      if (!Character.isLetter(first)) { start++; } 
   } 
   return true; 
}

Self Check 13.10

Is it faster to compute the triangle numbers recursively, as shown in Section 13.1, or is it faster to use a loop that computes 1 + 2 + 3 + . . . + width?

Permutations

Permutations

section_4/Permutations.java

Your browser does not support the <object> tag. Program Run:

Mutual Recursions

Syntax Diagrams for Evaluating an Expression

syntax diagram

Figure 3

Mutual Recursions

Syntax Tree for Two Expressions

another syntax tree

Mutually Recursive Methods

The getExpressionValue Method

public int getExpressionValue()
{
   int value = getTermValue(); 
   boolean done = false; 
   while (!done) 
   { 
      String next = tokenizer.peekToken(); 
      if ("+".equals(next) || "-".equals(next)) 
      { 
         tokenizer.nextToken(); // Discard "+" or "-" 
         int value2 = getTermValue(); 
         if ("+".equals(next)) value = value + value2; 
         else value = value - value2; 
      } 
      else 
      { 
         done = true; 
      } 
   } 
   return value; 
}

The getTermValue Method

The getTermValue method calls getFactorValue in the same way, multiplying or dividing the factor values.

The getFactorValue Method

public int getFactorValue() 
{ 
   int value; 
   String next = tokenizer.peekToken(); 
   if ("(".equals(next)) 
   { 
      tokenizer.nextToken(); // Discard "(" 
      value = getExpressionValue(); 
      tokenizer.nextToken(); // Discard ")" 
   } 
   else 
   { 
      value = Integer.parseInt(tokenizer.nextToken()); 
   } 
   return value; 
}

Using Mutual Recursions

To see the mutual recursion clearly, trace through the expression (3+4)*5:

section_5/Evaluator.java

Your browser does not support the <object> tag.

section_5/ExpressionTokenizer.java

Your browser does not support the <object> tag.

section5/ExpressionCalculator.java

Your browser does not support the <object> tag. Program Run:

Backtracking

Backtracking

Backtracking - Eight Queens Problem

Backtracking - Eight Queens Problem

Backtracking

Backtracking

Backtracking

Backtracking

Backtracking

Backtracking in the Four Queens Problem
solution to foure queens problem

section_6/PartialSolution.java

Your browser does not support this feature

section_6/Queen.java

Your browser does not support this feature

section_6/EightQueens.java

Your browser does not support this feature Program Run: