Big Java 4

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.4

In order to compute a power of two, you can take the next-lower power and double it. For example, if you want to compute 211 and you know that 210 = 1024, then 211 = 2 × 1024 = 2048. Write a recursive method public static int pow2(int n) that is based on this observation.

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?

Self Check 13.7

When does the recursive isPalindrome method stop calling itself?

Self Check 13.8

To compute the sum of the values in an array, add the first value to the sum of the remaining values, computing recursively. Of course, it would be inefficient to set up an actual array of the remaining values. Which recursive helper method can solve the problem?

Self Check 13.9

How can you write a recursive method public static void sum(int[] a) without needing a helper function?

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?

Self Check 13.11

You can compute the factorial function either with a loop, using the definition that n! = 1 × 2 × . . . × n, or recursively, using the definition that 0! = 1 and n! = (n – 1)! × n. Is the recursive approach inefficient in this case?

Self Check 13.12

To compute the sum of the values in an array, you can split the array in the middle, recursively compute the sums of the halves, and add the results. Compare the performance of this algorithm with that of a loop that adds the values.

Permutations

Permutations

section_4/Permutations.java

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

Self Check 13.13

What are all permutations of the four-letter word beat?

Self Check 13.14

Our recursion for the permutation generator stops at the empty string. What simple modification would make the recursion stop at strings of length 0 or 1?

Self Check 13.15

Why isn’t it easy to develop an iterative solution for the permutation generator?

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:

Self Check 13.16

What is the difference between a term and a factor? Why do we need both concepts?

Self Check 13.17

Why does the expression parser use mutual recursion?

Self Check 13.18

What happens if you try to parse the illegal expression 3+4*)5? Specifically, which method throws an exception?

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:

Self Check 13.19

Why does j begin at i + 1 in the examine method?

Self Check 13.20

Continue tracing the four queens problem as shown in Figure 6. How many solutions are there with the first queen in position a2?

Self Check 13.21

How many solutions are there altogether for the four queens problem?