Recursion

advertisement
Recursion
Powerful Tool
 Useful in simplifying a problem
(hides details of a problem)
 The ability of a function to call itself

A recursive call is a function call in
which the called function is the
same as the one making the call.
 We must avoid making an infinite
sequence of function calls (infinite
recursion).

Recursion: Divide and Conquer
Problem Solving Strategy




1) Divide problem (input instance) into one or
more subproblems of exactly the same type
as the original problem
2) Solve each subproblem
3) Combine solutions of subproblems to
obtain a solution for original input
NOTE: Looks like top-down design, except
subproblems are the exactly the same type as
the original problem
2
Finding a Recursive Solution

Each successive recursive call should bring you closer
to a situation in which the answer is known.

A case for which the answer is known (and can be
expressed without recursion) is called a base case.
(The answer is usually known in the smallest version of the
problem that requires the least amount of work, for example print
out a list of only 1 element.)

Each recursive algorithm must have at least one base
case, as well as the general (recursive) case
General format for
many recursive functions
if (some condition for which answer is known)
solution statement
// base case
else
recursive function call
// general case
SOME EXAMPLES . . .
Writing a recursive function to find
n! (factorial)
DISCUSSION
The function call Factorial(4) should have value
24, because it is 4 * 3 * 2 * 1 .
For a situation in which the answer is known),
the value of 0! is 1.
So our base case could be along the lines of
if ( number == 0 )
return 1;
cont.
Now for the general case . . .
The value of Factorial(n) can be written as
n * the product of the numbers from (n - 1) to 1,
that is,
n * (n - 1) * . . . * 1
or,
n *
Factorial(n - 1)
And notice that the recursive call Factorial(n - 1)
gets us “closer” to the base case of Factorial(0).
Recursive Solution
int Factorial ( int number )
// Pre: number is initialized and number >= 0.
{
if ( number == 0)
// base case
return 1 ;
else
// general case
return number + Factorial ( number - 1 );
}
Writing a recursive function to find
Nth Fibonacci number
DISCUSSION
Conceived in 13th century by Italian mathematician to
model how fast rabbits could breed
http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fibnat.html#Rabbits
Fibonacci series: 0, 1, 1, 2, 3, 5, 8, 13, 21, …
1st number is 0
2nd number is 1
3rd number is 2nd number + 1st number
…
nth number is the n-1st number + n-2nd number
cont.
For situation(s) in which the answer is known, the value of
1st Fibonacci number is 0 while the value of the 2nd is 1.
So our base cases are
if ( N == 1 )
return 0;
else if (N == 2)
return 1;
The general case is
The value of Nth Fibonacci number can be written as the sum of
the n-1st and n-2nd Fibonacci numbers or,
Fibonacci (N-1) + Fibonnaci (N-2)
Notice that the both recursive calls get us “closer” to the
base cases of Fibonnaci (1) or Fibonnaci (2).
Recursive Solution
int Fib ( int N )
// Pre: N is assigned and N >= 0.
{
if ( N == 1)
// base case
return 0;
else if ( N == 2)
// base case
return 1;
else
// general case
return Fib (N-1) + Fib ( N – 2 );
}
Three-Question Method of Verifying
Recursive Functions

Base-Case Question: Is there a nonrecursive way
out of the function that works?

Smaller-Caller Question: Does each recursive
function call involve a smaller case of the original
problem leading to the base case?

General-Case Question: Assuming each
recursive call works correctly, does the whole
function work correctly?
Fibonacci Example

Base cases: N=1 and N=2



when N=1, returns 0 ….correct by definition
when N=2, returns 1 …. correct by definition
Recursive calls smaller
1st passes N-1 and 2nd passes N-2 …check
 If we assume Fib(N-1) and Fib(N-2) give us correct
values of the N-1st and N-2 numbers in the series, and
the assignment statement adds them together …this
is the definition of the Nth Fibonacci number, so we
know the function works for N > 2.
 Since the function works for N=1, N=2, N>2, then it
works for N >= 1.
 Therefore the function works. (Induction Proof) 12

Another example where recursion
comes naturally

From mathematics, we know that
20 = 1

25 = 2 * 24
In general,
x0 = 1

and
and
xn = x * xn-1
for integer x, and integer n > 0.
Here we are defining xn recursively, in terms of
xn-1
// Recursive definition of power function
int Power ( int x, int n )
// Pre: n >= 0. x, n are not both zero
// Post: Function value = x raised to the power n.
{
// base case
if ( n == 0 )
return 1;
// general case
else
return ( x * Power ( x , n-1 ) ) ;
}
Of course, an alternative would have been to use looping
instead of a recursive call in the function body.
14
Recursive function to determine if value is in
array
PROTOTYPE
void DoRetrieveItem (ArrayType info, ItemType & item, bool & found, int
start, int end);
74
36
info[0]
[1]
...
Already searched
95
[start]
index
of
current
element
to
examine
75
29
47
...
[length -1]
Needs to be searched
void RetrieveItem (ArrayType info, ItemType & item, bool & end)
// Searches list for element with same key as item
// Pre: item’s key is initialized
// Post: if key of item exists in an item in the list, item will be set to that element and
found will
//
be set to true, otherwise found will be set to false
{
//initial call to recursive private member function
DoRetrieveItem (info, item, found, 0 ) ;
}
16
void DoRetrieveItem (ArrayType info, ItemType & item, bool & found, int start,
int end)
// Searches list info for value between positions start and length-1
// Pre: the sublist, list.info[start ] . . list.info[ list.length-1] contain values to be searched
// Post: if key of item exists in an item in the sublist info[start] . .. info[ list.end], item will
//
be set to that element and found will be set to true, otherwise found will be set to false
{
if (start == end )
// one base case
return false ;
else if ( info[start] == value )
// another base case
{
item = info [start];
return true ;
}
else
// general case
return DoRetrieveItem (info, item, found, start + 1, end) ;
}
17
void DoRetrieveItem (ArrayType info, ItemType & item, bool & found, int start,
int length)
//
//
Searches list for value between positions start and end
Pre: the sublist, list.info[start ] . . list.info[ list.end] contain values to be searched and is
SORTED
// Post: if key of item exists in an item in the sublist list.info[start] . .. list.info[ list.end], item will
//
be set to that element and found will be set to true, otherwise found will be set to false
{
int mid;
if (start > end)
found = false;
// base case
else
{
mid = (start + end)/2;
if (info[mid] == item )
// base case
{
item = info[mid];
found = true ;
}
else if (info[mid] < item )
// general case
DoRetrieveItem (info, item, found, start, mid-1);
else
// general case
DoRetrieveItem (info, item, found, mid+1, end);
}
18
“Why use recursion?”
The first couple of examples could have been
written without recursion, using iteration instead.
The iterative solution uses a loop, and the recursive
solution uses an if statement.
However, for certain problems the recursive
solution is the most natural solution.
In a future example, you will see a function to print a
stack in reverse. I will use both a loop and a
temporary container. It is easier to solve this
problem using recursion.
Download