JMU
Recursion
with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Recursion in Programming
Method/Function Calls Under the Hood
Method/Function Calls Under the Hood (cont.)
Tracing the Execution of a Recursive Algorithm
Tracing the Execution of a Recursive Algorithm (cont.)
For simplicity, let's trace a method/function for calculating the factorial.
public static int factorial(int n)
{
    int value;

    if   (n == 0) value = 1;
    else          value = factorial(n-1) * n;

    return value;
}
  
Tracing the Execution of a Recursive Algorithm (cont.)
As a more complicated example, let's trace a method/function for calculating Fibonacci numbers.
public static int fibonacci(int n)
{
    int value;

    if      (n == 0) value = 0;
    else if (n == 1) value = 1;
    else             value = fibonacci(n-1) + fibonacci(n-2);

    return value;
}
  
Definition vs. Implementation of Methods/Functions
Definition vs. Implementation of Methods/Functions (cont.)
Definition vs. Implementation of Methods/Functions (cont.)
Definition vs. Implementation (cont.)
Multiple return Statements in Recursive Methods/Functions

Some people find it easier to understand recursive methods/functions when they have multiple return statements.

public static int factorial(int n)
{
    if   (n == 0) return 1;
    else          return factorial(n-1) * n;
}
  
public static int fibonacci(int n)
{
    if      (n == 0) return 0;
    else if (n == 1) return 1;
    else             return (fibonacci(n-1) + fibonacci(n-2));
}
  
Thinking Recursively (i.e. Solving Problems with Recursion)

A Summary

An Example - Formatting a Number in any Base
An Example - Formatting a Number in any Base (cont.)
javaexamples/recursion/RadixFormatterV1.java
/**
 * A class that uses recursion to format a number in any base/radix
 * (in the interval [2, 36])
 *
 * @author  Prof. David Bernstein, James Madison Unversity
 * @verions 1.0
 */
public class RadixFormatter
{
    private final int    MAX_BASE    = 36;
    private final char[] DIGIT_TABLE = {'0','1','2','3','4','5','6','7','8',
                                        '9','A','B','C','D','E','F','G','H',
                                        'I','J','K','L','M','N','O','P','Q',
                                        'R','S','T','U','V','W','X','Y','Z'
                                       };



    /**
     * The "exposed" interface.  This function does
     * initialization and error-checking.
     *
     * @param n    The number to print
     * @param base The base to use
     * @return     The formatted String
     */
    public static String formatInBase(int n, int base)
    {
        String         returnString;
        
        returnString = "";
        if ((base <= 1) || (base > MAX_BASE)) 
        {
            returnString = "Invalid base: "+base;
        } 
        else 
        {
            if (n < 0) 
            {
                returnString = "-";
                n = -n;
            }

            returnString += formatRecursively(n, base);
        }

        return returnString;
    }




    /**
     * The recursive function
     *
     * @param n    The number to print
     * @param base The base to use
     */
    private static String formatRecursively(int n, int base)
    {
        // Base Case
        if (n < base) return DIGIT_TABLE[n % base];

        // Refinement
        return formatRecursively(n/base, base)  + DIGIT_TABLE[n % base];
    }
    
}
        
An Example - Searching through an Array
An Example - Searching through an Array (cont.)

An Unsorted Array

javaexamples/recursion/searchunsorted/Searcher.java (Fragment: 0)
    /**
     * Search through (part of) an array of Comparable objects
     * for a particular target.
     *
     * @param first  The first index to consider (inclusive)
     * @param last   The last index to consider (inclusive)
     * @param target The Comparable object to search for
     * @param data   The array of Comparable objects
     * @return       The index of the target (or -1 if it isn't found)
     */ 
    public static int search(int first, int last, 
                             Comparable target, Comparable[] data)
    {
        int      left, middle, result, right;
        

        result = -1;
        
        if (first == last) // The base case
        {
            if (target.compareTo(data[first]) == 0)
            {
                result = first;                
            }
        }
        else              // Refinement (i.e., shrink the search space)
        {
            middle = (first + last) / 2;
            // Note: This can be done more efficiently.
            //       You should think about how!
            left   = search(first, middle, target, data);
            right  = search(middle + 1, last, target, data);                
            result = Math.max(left, right);
        }
        return result;
    }
        
An Example - Searching through an Array (cont.)
An Example - Searching through an Array (cont.)

A Sorted Array Using One Base Case

javaexamples/recursion/search1/Searcher.java (Fragment: 0)
    /**
     * Search through (part of) a sorted array of Comparable objects
     * for a particular target.
     *
     * @param first  The first index to consider (inclusive)
     * @param last   The last index to consider (inclusive)
     * @param target The Comparable object to search for
     * @param data   The sorted array of Comparable objects
     * @return       The index of the target (or -1 if it isn't found)
     */ 
    public static int search(int first, int last, 
                             Comparable target, Comparable[] data)
    {
        int      left, middle, result, right;
        

        result = -1;
        
        if (first == last) // The base case
        {
            if (target.compareTo(data[first]) == 0)
            {
                result = first;                
            }
        }
        else              // Refinement (i.e., shrink the search space)
        {
            if ((target.compareTo(data[first]) >= 0) &&
                (target.compareTo(data[last])  <= 0))
            {
                middle = (first + last) / 2;
                // Note: This can be done more efficiently.
                //       You should think about how!
                left   = search(first, middle, target, data);
                right  = search(middle + 1, last, target, data);                
                result = Math.max(left, right);
            }
        }
        return result;
    }
        
An Example - Searching through an Array (cont.)

A Sorted Array Using Two Base Cases

javaexamples/recursion/search2/Searcher.java (Fragment: 0)
    /**
     * Search through (part of) a sorted array of Comparable objects
     * for a particular target.
     *
     * @param first  The first index to consider (inclusive)
     * @param last   The last index to consider (inclusive)
     * @param target The Comparable object to search for
     * @param data   The sorted array of Comparable objects
     * @return       The index of the target (or -1 if it isn't found)
     */ 
    public static int search(int first, int last, 
                             Comparable target, Comparable[] data)
    {
        int      left, middle, result, right;
        

        result = -1;
        
        // One base case
        if (first == last) 
        {
            if (target.compareTo(data[first]) == 0)
            {
                result = first;                
            }
        }
        // Another base case
        else if ((target.compareTo(data[first]) < 0) ||
                 (target.compareTo(data[last])  > 0))
        {
            result = -1;
        }
        // Refinement (i.e., shrink the search space)
        else              
        {
            middle = (first + last) / 2;
            // Note: This can be done more efficiently.
            //       You should think about how!
            left   = search(first, middle, target, data);
            right  = search(middle + 1, last, target, data);                
            result = Math.max(left, right);
        }
        return result;
    }
        
An Example - Making Change
An Example - Making Change (cont.)

A (Really Slow) Recursive Algorithm

javaexamples/recursion/ChangeMaker.java
/**
 * A class that uses recursion to make change
 *
 * @author  Prof. David Bernstein, James Madison Unversity
 * @verions 1.0
 */
public class ChangeMaker
{

    /**
     * Determine the minimum number of coins needed to make change
     *
     * @param coins  The array of coin values
     * @param amount The amount of change
     *
     * @returns      The number of coins
     */
    public int change(int[] coins, int amount)
    {
        int i, j, min, number;
        
        min = amount;
        
        // If we can make change with one coin then we are done
        //
        for (i=0; i < coins.length; i++) {
            
            if (coins[i] == amount) return 1; // The base case
        }
        
        // Refine the solution
        //
        for (j=1; j <= (amount/2); j++) {
            
            number = change(coins, j) + change(coins, amount-j);
            if (number < min) min = number;
        }
        
        return min;
    }

}
    




        
Recursive Methods in a Class
An Example - Formatting a Number in any Base

The public method does not require the caller to know anything about the recursion.

The base attribute is used to keep track of the base (rather than passing it as a parameter).

javaexamples/recursion/RadixFormatter.java
/**
 * A class that uses recursion to format a number in any base/radix
 * (in the interval [2, 36])
 *
 * This version uses an attribute to keep track of the base.
 *
 * @author  Prof. David Bernstein, James Madison Unversity
 * @verions 2.0
 */
public class RadixFormatter
{
    private final int      MAX_BASE    = 36;
    private final String[] DIGIT_TABLE = {"0","1","2","3","4","5","6","7","8",
                                          "9","A","B","C","D","E","F","G","H",
                                          "I","J","K","L","M","N","O","P","Q",
                                          "R","S","T","U","V","W","X","Y","Z"
                                         };
    private int base;
    

    /**
     * Constructor
     */
    public RadixFormatter(int base)
    {
        this.base = base;
    }

    /**
     * The "exposed" interface.  This function does
     * initialization and error-checking.
     *
     * @param n    The number to print
     * @return     The formatted String
     */
    public String formatInBase(int n)
    {
        String formatted = "";
        
        if ((base <= 1) || (base > MAX_BASE)) 
        {
            formatted = "Invalid base: "+base;
        } 
        else 
        {
            if (n < 0) 
            {
                formatted = "-";
                n = -n;
            }
            
            formatted += formatRecursively(n);
        }

        return formatted;
    }




    /**
     * The recursive function
     *
     * @param n    The number to print
     */
    private String formatRecursively(int n)
    {
        // Base Case
        if (n < base) return DIGIT_TABLE[n % base];
        
        // Refinement
        return formatRecursively(n/base) + DIGIT_TABLE[n % base];
    }
    
}
        
An Example - Making Change

An attribute can be used so that the coins array does not have to be a parameter of the recursive method.

javaexamples/recursion/CashRegister.java
/**
 * A class that uses recursion to make change
 *
 * @author  Prof. David Bernstein, James Madison Unversity
 * @verions 1.0
 */
public class CashRegister
{
    private int[]       coins;
    
    /**
     * Explicit Value Constructor.
     *
     * @param coins   The face value of the coins to use
     */
    public CashRegister(int[] coins)
    {
        this.coins = new int[coins.length];        
        System.arraycopy(coins, 0, this.coins, 0, coins.length);
    }
    

    /**
     * Determine the minimum number of coins needed to make change
     *
     * @param amount The amount of change
     * @returns      The number of coins
     */
    public int change(int amount)
    {
        int i, j, min, number;
        
        min = amount;
        
        // If we can make change with one coin then we are done
        //
        for (i=0; i < coins.length; i++) {
            
            if (coins[i] == amount) return 1; // The base case
        }
        
        // Refine the solution
        //
        for (j=1; j <= (amount/2); j++) {
            
            number = change(j) + change(amount-j);
            if (number < min) min = number;
        }
        
        return min;
    }

}
    




        
Rewriting Recursive Methods/Functions
Tail Recursion

Is this implementation tail-recursive? In other words, what is the last action performed?

    public static int factorial(int n)
    {
      if   (n == 0) return 1;
      else          return n*factorial(n-1);
    }
  
Tail Recursion (cont.)

A tail-recursive implementation:

    public static int factorial(int n, int accumulator)
    {
      if   (n == 0) return accumulator;
      else          return factorial(n-1, n*accumulator);
    }
  
Tail Recursion (cont.)

Converting a tail-recursive implementation to an iterative implementation:

    public static int factorial(int n, int accumulator)
    {
      while (n != 0)
      {
          accumulator *= n;
          n -= 1;
      }
      return accumulator;
    }