Вы находитесь на странице: 1из 30

Data Structures and

Algorithms for Information


Processing
Some Notes on Recursion

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Recursion
Weve seen several examples of the use
of recursion
Well take a closer look at recursion as a
style of programming
Lends itself to analytical methods;
proving program properties

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Verifying Program Properties
How can we be sure that a program is
correct?
Debug
Test cases
Make sure output matches another
program
...
None of these give absolute assurance

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Imperative Programming
The usual style in Java, using
commands
Programs are written by create data
(state) and storing it in variables
Flow of control insures that correct
sequence of assignments is executed

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Applicative Programming
No references to other objects
No side effects (assignments, output...)
Some advantages:
Functions only return values
No need for loops
Easier to prove properties
A different programming style, and a
different way to think about
programming
90-723: Data Structures
and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Recursion
General pattern:

recursive_fn(params) {
if () return some_value;
else ... recursive_fn(new_params) ...
}

A recursive function call is made


somewhere in the body of the function

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Tail Recursion
General pattern:

tail_recursive_fn(params) {
if () return some_value;
else return tail_recursive_fn(new_params)
}

Tail recursive: the function does no


work after the recursive call

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Tail Recursion
Usual recursive factorial

// Precondition: n >= 0
static int fact1(int n) {
if (n==0) return 1;
else return n*fact1(n-1);
}

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Tail Recursion
Tail recursive factorial

static int fact2(int n) { // Precondition: n >= 0


return fact2_aux(n, 1);
}
static int fact2_aux(int n, int accum) {
if (n==0) return accum;
else return fact2_aux(n-1, n*accum);
}

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Execution Trace
fact1(5)
5*fact1(4)
5*4*fact1(3)
5*4*3*fact1(2)
5*4*3*2*fact1(1)
5*4*3*2*1*fact1(0)
5*4*3*2*1*1
=> 120

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Execution Trace
fact2(5)
fact2_aux(5,1)
fact2_aux(4,5)
fact2_aux(3,20)
fact2_aux(2,60)
fact2_aux(1,120)
fact2_aux(0,120)
=> 120

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Example of Non-Tail
Recursion
// Precondition: y > 0
static int mult (int x, int y) {
if (y==1) return x;
else return x + mult(x, y-1);
}
Addition operation carried out after the
recursive call

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Tail Recursion (cont)
Tail recursive functions can be more
efficient
Often easier to prove properties of tail
recursive functions
correctness, termination, cost
technique: induction

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Example: fact2
Want to prove using induction that
fact2(n) => n!

We do this by proving an appropriate


property of the auxiliary function:
fact2_aux(n, p) => n! * p

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Example: fact2 (cont)
Base case: n=0
for all p
fact2_aux(0, p) => p = 0! * p

Inductive step: n > 0:


Assume true for n-1
For all p
fact2_aux(n-1, p) =>(n-1)! * p

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Example: fact2 (cont)
Inductive step: n > 0:
Assume true for n-1
For all p
fact2_aux(n-1, p) =>(n-1)! * p
So:
fact2_aux(n, p) =>
fact2_aux(n-1, n*p) =>
(n-1)! * (n*p) = (n*(n-1)!)*p = n!*p

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Example: fact2 (cont)
Proving termination by induction:
Base case:
fact2_aux(0, p) => return p
Inductive case:
terminates if operator * terminates

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Tail recursive reverse
We can easily get an O(n)
implementation using tail recursion:
List rev2_aux(List x, List y) {
if (x==null) return y;
else return
rev2_aux(x.next(), new List(x.value(), y))
}
List reverse2(x) { return rev2_aux(x, null); }

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Cost of rev2_aux
Let Cost[n,m] be the number of
operations for rev2_aux(x,y) with
x.length()=n and y.length() = m
Cost[0,m] = A (constant)
n>0, Cost[n,m] = Cost[n-1,m+1] + B
Thus, Cost[n,m] = A + nB = O(n)

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Fibonacci Numbers
Want fib(0)=1, fib(1)=1,
fib(n) = fib(n-1) + fib(n-2) if n>1
Simple recursive implementation:
// Precondition: n>=0
int fib(int n) {
if (n < 2) return 1;
else return fib(n-1)+fib(n-2);
}
90-723: Data Structures
and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Fibonacci Numbers
Cost is the same as the Fibonacci
numbers themselves!

fib(n) rises exponentially with n:


fib(n) > (1.618)^n / 2

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Imperative version
int i=1;
int a=1, b=1;
while (i<n) {
int c = a+b; // fib(i+1)
a = b;
b = c;
i++;
}

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Recursive Version

Define an auxiliary function fib_aux

Use two accumulator variables, one set


to fib(i-1), the other to fib(i)

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Recursive Version
int fib_aux (int n, int i, int x, int y) {
if (i==n) return y;
else return fib_aux(n, i+1, y, x+y);
}
int fib(int n) {
if (n==0) return 1;
else return fib_aux(n, 1, 1, 1);
}

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Backtracking Search
General pattern:
Test if current position satisfies goal
If not, mark current position as visited
and make a recursive call to search
procedure on neighboring points
Exhaustive search, terminates as soon
as goal is found

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Backtracking search:
simple example
The bear game:
Start with initial number of bears
Need to reach goal number within a certain
number of steps
Possible moves:
Add incr number of bears
If even divide current number in half
Suppose initial=10, goal=180, incr=50,n=5

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Backtracking search:
simple example
Public static boolean bears (int initial, int goal,
int incr, int n) {
if (initial == goal) return true;
else if (n==0) return false;
else if (bears(initial+incr, goal, incr, n-1))
return true;
else if (initial % 2 == 0)
return bears(initial/2, goal, incr, n-1);
else return false;
}
90-723: Data Structures
and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
Backtracking search:
simple example
Why does this program
terminate?
What if we remove the restriction
on the number of steps?

90-723: Data Structures


and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.
General Backtracking
boolean solve(Configuration conf) {
if(no more choices) return (conf is goal)
for (each possible choice) {
make choice to conf
if(solve(conf)) return true Try with:
unmake choice of conf N-Queens
} Sudoku
return false :
Etc.
}
90-723: Data Structures
and Algorithms for From Stanford Video on Program
Information Processing Abstractions Lecture 11
Copyright 1999, Carnegie Mellon. All Rights Reserved.
Benefits of Recursion
Recursion can often be implemented
efficiently
Requires less work (programming and
computation)
Tail recursive versions require less stack
space
The code is typically much cleaner than
imperative versions
Sometimes easier to prove program
properties
90-723: Data Structures
and Algorithms for Some Notes on Recursion
Information Processing Copyright 1999, Carnegie Mellon. All Rights Reserved.

Вам также может понравиться