Recursion

advertisement
Recursion
Recursion
1
Recursion
What kind of problem is “recursive”?
Recursive problems are those problems where in order to solve the
original problem you have to solve one or more identical but smaller
version(s) of the same problem.
i.e.,
To solve problem of “size n”, first solve the
of “size n-1 or less”.
same problem
Examples:
• Binary Search
• Finding nth Fibonacci number
• Finding Factorials
How are each
of these
• Finding exponents
• TOH
• Finding your way out of maze
recursive
problems?
• 8-queens problem
• Graph traversal problems
•…
Recursion
2
Recursion
First understanding a method and method call:
… method(int k){
//method implementation
//solves problem of size k
}
For a method, the method call defines the problem size:
Solve a problem of “size n”
- method(n)
Solve a problem of “size n-1”
- method(n-1)
Solve a problem of “size n/2”
- method(n/2)
Solve a problem of “size 1”
- method(1)
Implicit sizes
Solve a problem over an array
of n elements
- method(int[] array,
int left, int right);
Recursion
3
Recursive problems and methods:
Problem:
Find the exponent xn
Recursive problems are those problems where in order to solve the
original problem you have to solve one or more identical but smaller
version(s) of the problem until you reach the trivial or base case.
Recursive solution 1:
Recursive solution 2:
xn
xn = xn-1 * x1
First solve
xn-1
xn/2 * xn/2, if n is even
xn/2 * xn/2 * x, if n is odd
=
To find: xn
First solve xn/2
To find: xn
…
x2 = x1 * x1
x1 = x0 * x1
x0 = 1
Trivial or
base case Recursion
…
x2 = x1 * x1
x1 = x0 * x0 * x1
x0 = 1
4
Recursive problems and methods:
Problem:
Find the exponent xn
Corresponding method signature:
/**
* purpose of this method is to calculate x^n
* @param x - the base
* @param n - the exponent, n >= 0
* @return x^n
*/
public static double power(double x, int n)
Usage:
Solve 5^3
-
power(5,3);
Solve 0.031^9
-
power(0.031,9);
Solve 10472834^0
-
power(10472834,0);
Solve x^n
-
power(x,n)
Solve x^(n-1)
-
power(x,n-1)
Recursion
5
Recursive problems and methods:
Connecting the problem and the code
The problem
xn = xn-1 * x1 +
The method signature
/**
* purpose of this method is to calculate x^n
* @param x - the base
* @param n - the exponent, n >= 0
* @return x^n
*/
public static double power(double x, int n)
Solve xn = power(x,n) = power(x,n-1) * x
Recursion
6
Recursive problems and methods:
Corresponding method:
Problem:
Find the exponent xn
Recursive solution:
xn = xn-1 * x1
Solve x^(n-1)
/**
* purpose of this method is to calculate x^n
* @param x - the base
* @param n - the exponent, n >= 0
* @return x^n
*/
public static double power(double x, int n)
{
if (n == 0)
Solve x^n
return 1;
Base case always first!
…
x1 = x0 * x1
x2 = x1 * x1
Recursion next
x0 = 1
double ans = power(x,n-1) * x;
return ans;
}
Recursion
7
Recursive problems and methods:
Trace the following call:
…
System.out.println(power(5,4));
...
Recursion
8
Recursive problems and methods:
Corresponding method:
Problem:
Find the exponent xn
Recursive solution:
xn
=
/**
* purpose of this method is to calculate x^n
* @param x - the base
* @param n - the exponent, n >= 0
* @return x^n
*/
public static double power(double x, int n)
xn/2 * xn/2, if n is even
xn/2 * xn/2 * x, if n is odd
{
if (n == 0)
Solve xn/2
double xn;
double xno2 = power(x,n/2);
if (n%2 == 0) xn = xno2 * xno2;
else
xn = xno2 * xno2 *x;
Solve x^n
…
x2 = x1 * x1
x1 = x0 * x0 * x1
x0 = 1
return 1;
return xn;
}
Recursion
9
Recursion - Can you do this?
Find x! as follows:
0! = 1
x! = x*(x-1)!
/**
* purpose of this method is to calculate n!
* @param n - the value whose factorial we have to find
* @return n!
*/
public static double factorial(int n)
Recursion
10
Recursion - another example:
Problem:
f(n) = 1, when n is 0 or 1
Base case
f(n) = f(n-1) + f(n-2) when n > 1
Recursive case
/**
* Finds the nth Fibonacci number
* @param n - the index of the Fibonacci number to find, n >= 0
* @return nth Fibonacci number
*/
public static int fibonacci(int n){
if ((n==0) || (n==1)) return 1;
//apparently, n is not 0 or 1
return fibonacci(n-1) + fibonacci(n-2);
}
Trace the following:
System.out.println(fibonacci(4));
Recursion
11
Recursion:
Inherent cost of recursion:
A lot of system overhead associated with method calls
Advantages of recursion:
Provides a clear readable intuitive solution to the problem.
Recursion
12
How to problem solve recursively
Given a problem of size n ask the following question:
“ASSUMING I knew the solution to a smaller but identical sub problem,
can I use that answer to solve my current problem?”
If “yes”, how do you proceed?
1. Imagine m() to be a method that will solve all such smaller problems.
2. Imagine calling m() and incorporate the solution from m() to solve
current problem. [Think carefully about the signature of m().]
3. What size is the smallest sub problems? (Note: smallest sub problem
cannot be broken apart because if it could that would imply a still smaller
problem!)
4. All such small sub problems found in 3 are your base cases.
5. Replace all m()‘s with a call to your self.
6. Put all the pieces together.
Recursion
13
How to problem solve recursively
Problem: Write a method to find xn
Can this problem be solved recursively?
“ASSUMING I knew the solution …
1. Imagine a method m() that will solve this problem, and call it
m(x,n-1) -> returns an int, xn-1
2. Imagine calling m() and incorporating that solution to solve …
int x_to_n = x * m(x, n-1)
3. What size is the smallest sub problems?
n = 0, x0 = 1
4. All such small sub problems found in 3 are your base cases.
if (n == 0) return 1;
5. Replace all m()‘s with a call to your self.
int x_to_n = x * power(x,n-1);
Recursion
14
How to problem solve recursively
6. Put all the pieces together.
public static int power(int x, int n){
if (n == 0) return 1;
//apparently, n is not zero
int x_to_n = x * power(x,n-1);
return x_to_n;
}
Recursion
15
The (classic) Towers of Hanoi problem
Objective:
To move n rings from any peg start peg (s) to any destination peg (d), without
1. moving more than one ring at a time, and
2. without placing a larger ring on top of a smaller ring.
peg 1
peg 2
peg 3
?
s = 1, d = 3
Analysis/algorithm:
Is it recursive?
What would method m() look like?
Can we phrase the solution in terms of m()?
Recursion
16
Towers of Hanoi problem
/**
* The purpose of this method is to solve the towers of Hanoi
* problem for n rings being moved amongst 3 pegs, numbered 1,2
* and 3.
* @param n - the number of rings to move
* @param o - the origination peg (where the rings currently are)
* @param d - where the rings should be moved too
*/
public static void toh(int n, int o, int d){
//check for base
if (n == 1)
System.out.println(“move a ring from “+o+” to “+d);
else{
toh(n-1,o, 6-o-d);
System.out.println(“move a ring from “+o+” to “+d);
toh(n-1, 6-o-d, d);
}
}
Recursion
17
Towers of Hanoi problem
Trace: toh(3,1,3)
TOH(3,1,3)
TOH(2,1,2)
TOH(1,1,3)
TOH(2,2,3)
TOH(1,3,2)
TOH(1,2,1)
TOH(1,1,3)
What is the performance of toh()?
Recursion
18
Recursion and arrays - print an array out, backwards
Problem: print an array backwards.
Can this problem be solved recursively?
1. Imagine a method m() that will solve this problem.
[Think carefully about the signature of such a method.]
2. Imagine calling m() and incorporating that solution to solve …
3. What size is the smallest sub problems?
4. All such small sub problems found in 3 are your base cases.
5. Replace all m()‘s with a call to your self. [What happens if the signatures don’t
match?]
Performance?
6. Put all the pieces together.
Recursion
19
Searching an array
Problem: Search and array, A, of integers for a value B. If found return location
index; otherwise return –1.
Performance?
Recursion
20
Recursion - Divide and Conquer - Binary search
/**
* This method searches an array of sorted Comparable objects
* @param a - the array of sorted Comparable objects
* @val - the value searched for
* @l - the left starting index
* @r - the right starting index
* @return array index of value if found; -1 otherwise.
*/
public static int binarySearch(int[] a, int val, int l, int r){
if (l >
int mid
if (val
if (val
else
r)
= (l+r)/2;
== a[mid])
< a[mid])
return -1;
//not found
return mid; //found
return binarySearch(a,val,l,mid-1);
return binarySearch(a,val,mid+1,r);
}
Performance?
Recursion
21
Sorting an array
Problem: Sort an integer array, A.
What recursive strategies can we use, if any? Can you come up with any?
Recursion
22
Recursion - Divide and Conquer - Merge Sort
/** This method will sort an array using merge sort*/
public static int[] sort(int a[]){
return mergeSort(a, l, r);
}
/** This method will sort an array of Comparable objects
* using Merge sort
* @param array - the array to sort
* @param l - the left index
* @param r - the right index
*/
public static void mergeSort(int[] array, int l, int r){
if (l < r){
int mid = (l+r)/2;
//divide in half
mergeSort(array, l, mid); //sort each half
mergeSort(array, mid+1, r);
merge(array, l,mid,r);
//merge sorted halves
}
}
public static void merge(int[]
1. create a temp array to
2. merge the two halves
3. Make sure all elements
4. Copy elements from the
}
array, int l, int mid, int r){
hold the merging halves
of the two halves are in the temp array
temp array back to array.
Performance?
Recursion
23
Recursion - Divide and Conquer - Merge Sort
public static void merge(int[] array, int l, int mid, int r){
//create an array
int[] temp = new int[r+1];
//merge
int li=l, ri = mid+1, ti = l-1;
while ((li <= mid) && (ri <= r)){
ti++;
if (array[li] < array[ri]){
temp[ti] = array[li];
li++;
}
else{
temp[ti] = array[ri];
ri++;
}
}
// Make sure all elements of the two halves are in the temp array
for(int i=li; i<=mid; i++, ti++)
temp[ti] = array[i];
for(int i=ri; i<=r; i++, ti++)
temp[ti] = array[i];
//Copy elements from the temp array back to array.
for(int i=l; i<=r; i++)
array[i] = temp[i];
}
Recursion
24
Recursion - Divide and Conquer - Quick Sort
Problem: Sort an integer array, A.
public static int[] sort(int[] a)
Can this problem be solved recursively?
Imagine 1:
Move elements in array into the left and right of the array such that all the
elements on the left are less than some pivot value and all the elements
to the right are greater. Imagine that you know this break even index.
Imagine 2:
Imagine that m() is a method that will sort an array’s elements between l
and r:
int[] m(int[] a, int l, int r)
2. Imagine calling m() and incorporating that solution to solve …
int pivIndex = partition(a, l,r);
m(a,l,pivIndex-1);
m(a,pivIndex+1, r);
3. Base case(s)
if (l < r) {
Recursion
25
Recursion - Divide and Conquer - Quick Sort
/** This method will sort an array using quick sort*/
public static int[] sort(int a[]){
return quiskSort(a, l, r);
}
/** This method will sort an array of Comparable objects
* using Quick sort
* @param array - the array to sort
* @param l - the left index
* @param r - the right index
*/
private static void quickSort(int[] array, int l, int r){
if (l < r){
int pivot = partition(array,l,r);
quickSort(array, l, pivot-1);
//sort each half
quickSort(array, pivot+1, r);
}
}
private static void partition(int[] array, int l,int r){
0. Pivot value is array[l]
1. Scan from left to right and right to left moving items larger
than pivot to the right and those smaller than pivot to the
left
2. Move pivot to its sorted position
Performance?
3. return pivot index
}
Recursion
26
Recursion - Divide and Conquer - Quick Sort
public static void partition(int[] array, int l,int r){
//Pivot value is array[l]
int pivotVal = array[l];
//Scan from left to right and right to left moving items larger
//than pivot to the right and those smaller than pivot to the left
int li = l, ri = r;
while (li < ri){
while ((pivotVal > array[li]) && (li<ri)) li++;
while (pivotVal < array[ri]) ri--;
if (li<ri){
int temp = array[li];
array[li] = array[ri];
array[ri] = temp;
li++; ri--;
}
}
//Move pivot to its sorted position
array[l] = array[ri];
array[ri] = pivotVal;
//return pivot index
return ri;
}
Recursion
27
Download