|
Recursion
with Examples in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
public static int factorial(int n)
{
int value;
if (n == 0) value = 1;
else value = factorial(n-1) * n;
return value;
}
public static int factorial(int n)
{
int value;
if (n == 0) value = 1;
else value = factorial(n-1) * n;
return value;
}
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;
}
public static int factorial(int n)
{
int value;
if (n == 0) value = 1;
else value = factorial(n-1) * n;
return value;
}
public static int factorial(int n)
{
int value;
value = 1;
for (int i=2; i<=n; i++)
{
value *= i;
}
return value;
}
public static int factorial(int n)
{
int value;
int[] f={1,1,2,6,24,120,720,5040,40320,
362880,3628800,39916800,479001600};
if (n > 12) value = -1; // Or throw an exception
else value = f[n];
return value;
}
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));
}
/**
* 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];
}
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
}
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).
/**
* 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 attribute can be used so that the coins array does not have
to be a parameter of the recursive method.
/**
* 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;
}
}
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);
}
A tail-recursive implementation:
public static int factorial(int n, int accumulator)
{
if (n == 0) return accumulator;
else return factorial(n-1, n*accumulator);
}
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;
}