DATA STRUCTURES
AND ALGORITHMS
◻
Recursion
◻
Recursion v/s Iteration
3
Recursion
Recursive Definition – one that defines something in
terms of itself
Recursion – A technique that allows us to break down
a problem in to one or more subproblems that are
similar in form to the original problem.
4
Iterative Factorial
Iterative definition
N! = N * (N-1) * (N-2) * … * 3 * 2 * 1
int factorial (int n) {
int i, result; result = 1;
for (i = 1; i <= n; i++) { result = result * i; }
5
Recursive Factorial
Recursive N! definition
N! = 1 if N = 0
= N * (N-1)! Otherwise
int factorial ( int n) {
if (n == 0) return (1);
6
Iterative vs Recursive factorial
Iterative
1.
2 local variables
2.3 statements
3.
Saves solution in an
intermediate variable
Recursive
1.
No local variables
2.One statement
3.
Returns result in
single expression
7
How does it work?
Each recursive call creates an “activation
record” which contains
local variables and parameters
return address
8
Iterative Power
Iterative definition
XN = X * X *X ….. * X (N factors)
double power(double number, int exponent) {
double p = 1;
for (int i = 1; i <= exponent; i++) p = p * p;
9
Recursive Power
Recursive definition XN = 1 if N = 0
= X * X(N-1) otherwise
double power(double number, int exponent) // Precondition: exponent >= 0
{
if (exponent == 0) return (1);
10
Recursive String Reversal
void RString (char *s, int len)
{
if (len <= 0) return;
RString (s+1, len-1);
cout << *s ;
11
Recursive Data Structures
Array -- a set of data elements store in contiguous memory cells Array -- zero elements OR
a single data element OR
12
Iteratively Sum an Array
int SumArray (int a[ ], int size) {
int j, sum = 0;
for ( j = 0; j < size; j++ ) sum += a[ j ];
13
Recursively Sum an Array
int SumArray ( int a [ ], int size) {
if (size == 0) return 0; else
14
Approach to Writing Recursive Functions
Using “factorial” as an example,
1. Write the function header so that you are sure
what the function will do and how it will be
called.
[For factorial, we want to send in the integer
for which we want to compute the factorial.
And we want to receive the integer result back.]
15
Approach (cont’d)
2. Decompose the problem into subproblems (if necessary).
For factorial, we must compute (n-1)!
3. Write recursive calls to solve those subproblems whose form is similar to that of the original problem.
There is a recursive call to write:
16
Approach (cont’d)
4. Write code to combine, augment, or
modify the results of the recursive call(s)
if necessary to construct the desired
return value or create the desired side
effects.
When a factorial has been computed,
the result must be multiplied by the
current value of the number for which
the factorial was taken:
17
Approach (cont’d)
5. Write base case(s) to handle any
situations that are not handled
properly by the recursive portion of
the program.
The base case for factorial is that if n=0,
the factorial is 1:
18
Ensuring that Recursion Works
Using “factorial” as an example,
1. A recursive subprogram must have at
least one base case and one recursive
case (it's OK to have more than one base
case and/or more than one recursive case).
The first condition is met, because if
(n==0) return 1 is a base case, while the
"else" part includes a recursive call
19
Does It Work? (cont’d)
2. The test for the base case must execute
before the recursive call.
If we reach the recursive call, we must
have already evaluated if (n==0); this is
20
Does It Work? (cont’d)
3. The problem must be broken down in such a way that the recursive call is closer to the base case than the top-level call.
21
Does It Work? (cont’d)
4. The recursive call must not skip over the
base case.
22
Does It Work? (cont’d)
5. The non-recursive portions of the subprogram
must operate correctly.
Assuming that the recursive call works properly,
we must now verify that the rest of the code
works properly. We can do this by comparing the
code with our definition of factorial. This definition
says that if n=0 then n! is one. Our function correctly
returns 1 when n is 0. If n is not 0, the definition
says that we should return (n-1)! * n. The recursive
call (which we now assume to work properly)
returns the value of n-1 factorial, which is then
23
Recursion vs. Iteration
Recursion
∙
Usually less code – algorithm can be
easier to follow (Towers of Hanoi,
binary tree traversals, flood fill)
∙
Some mathematical and other
algorithms are naturally recursive
24
Recursion vs. Iteration (cont’d)
Iteration
∙
Use when the algorithms are easier
to write, understand, and modify
(especially for beginning programmers)
∙
Generally, runs faster because there
is no stack I/O
25
Direct Recursion
A C function is directly recursive if it contains an explicit call to itself
Int foo (int x) {
26
Indirect Recursion
A C function foo is indirectly recursive if it contains a call to another function that ultimately calls foo.
int foo (int x){
if (x <= 0) return x; return bar(x);
}
int bar (int y) {
27
Tail Recursion
A recursive function is said to be
tail recursive
if
there is no pending operations performed on return
from a recursive call
28
factorial is non-tail recursive
int factorial (int n)
{
if (n == 0) return 1;
return n * factorial(n – 1);
}
Note the “pending operation” (namely the
29
Tail recursive factorial
int fact_aux (int n, int result) {
if (n == 1) return result;
return fact_aux (n – 1, n * result);
}
factorial (int n) {
return fact_aux (n, 1);
30
Linear Recursion
A recursive function is said to be linearly recursive when no pending operation invokes another recursive call to the function.
int factorial (int n)
{
if (n == 0) return 1;
31
Linear Recursive Count_42s
int count_42s(int array[ ], int n) {
if (n == 0) return 0;
if (array[ n-1 ] != 42) {
return (count_42s( array, n-1 ) ); }
32
Tree Recursion
A recursive function is said to be tree recursive (or non-linearly recursive when the pending operation does invoke another recursive call to the function.
33
Fibonacci Numbers
The Fibonacci numbers can be recursively
defined by the rule:
fib(n) = 0 if n is 0,
= 1 if n is 1,
= fib(n-1) + fib(n-2) otherwise
For example, the first seven Fibonacci numbers are
Fib(0) = 0
Fib(1) = 1
34
Tree Recursive Fibonacci
// Note how the pending operation (the +)
// needs a 2
ndrecursive call to fib
int fib(int n) {
if (n == 0) return 0;
if (n == 1) return 1;