Copyright © Curt Hill 2006-2007 Recursion A Different Way to Think and Solve Problems.
-
Upload
clemence-chambers -
Category
Documents
-
view
218 -
download
0
Transcript of Copyright © Curt Hill 2006-2007 Recursion A Different Way to Think and Solve Problems.
Copyright © Curt Hill 2006-2007
Recursion
A Different Way to Think and Solve Problems
Copyright © Curt Hill 2006-2007
Definition
• A recursively defined term is somehow defined in terms of itself
• A recursive function generally calls itself– It may also call a sequence of functions that
eventually call it back
• The term recursion comes from the mathematical term of a recurrence relation
Copyright © Curt Hill 2006-2007
Recurrence Relation
• Usually used to define the terms of series or sequence
• The recurrence relation for the Fibonacci sequence is:an = an-1 + an-2
• Typically a Fibonacci sequence starts with:a0 = a1 = 1 giving:1 1 2 3 5 8 13 21 34 55 …
Copyright © Curt Hill 2006-2007
Recursive Definition
• A recursive definition almost always has two or more parts
• One deals with startup or boundary conditions– This one makes no self reference
• The other is self-referencing– Always adds something before or after
the self-reference
Copyright © Curt Hill 2006-2007
Definition
• An item that is somehow defined in terms of itself
• Circular ≠ recursive– Circular definition adds no information
to definition– Recursive definition usually is multipart
• One part is non recursive• Even recursive parts add information
• Recursion is a generalization of looping
Copyright © Curt Hill 2006-2007
Circular vs. Recursive
• A circular definition adds nothing to the knowledge of the reader– A rose is a rose is a rose is a rose
• A recursive definition is partially based on itself– Yet it is able to completely specify the
result
• Both data and functions or methods may be recursively defined
Copyright © Curt Hill 2006-2007
Consider this Shape
Copyright © Curt Hill 2006-2007
Where Do We See These?• Recursive functions
– Function calls itself– Mutual recursion – a set of functions call
each other so that a call to another function generates a call to itself• A calls B and B calls A• A calls B, B calls C, C calls A
• Recursive data structures– Lists– Trees– Graphs
Copyright © Curt Hill 2006-2007
Consider a recursive definition
• Recursive definition of a linked list• A list may be:
– Empty– Item followed by a list
• Now consider how this becomes code
Copyright © Curt Hill 2006-2007
A Linked List• Two classes:class ListItem { Data d; // carried data ListItem * next; friend class List; ListItem(); // private default }; // everything is privateclass List{ ListItem * root; public: void add(Data d); bool isPresent(Data d); …};
Copyright © Curt Hill 2006-2007
Discussion
• The pointer represents the list– Either the next in the ListItem or – The root in List
• May be NULL– Which is the empty list
• May refer to a ListItem– Which is an item followed by a list
• Trees are more recursive but await the data structures course
Copyright © Curt Hill 2006-2007
Why Recursion?• Recursion is the generalization of
looping• This is loosely translated into this:• Any loop may be made into a
recursive function• Some recursive functions cannot
be made into loops• However, every recursive function
may be converted to a loop with an auxiliary data structure
Copyright © Curt Hill 2006-2007
Recursive Functions
• A recursive function must follow the same rules as a recursive definition– Except as translated to execution
• They are:• One or more non-recursive paths• Each recursive path moves the
function closer to a non-recursive path
• Failure to follow this cause problems
Copyright © Curt Hill 2006-2007
Recursive Functions
• A routine that calls itself or• A routine that initiates a call that
calls itself– A calls B– B calls C– C calls A– Syntax
• In C++ everything must be declared before it is used
• We then merely declare the prototype before it is used
Copyright © Curt Hill 2006-2007
Forms of Recursion
• Most recursive functions call themselves
• Two functions that call each other are called mutually recursive:int a(…);int b(…){ … x = a(…); … }int a(…){ … y = b(…); … }
• Notice the need for a prototype• The chain could be longer than two
Copyright © Curt Hill 2006-2007
Factorial
• Definition of factorial: N! =– IF n > 1 THEN N * (n-1)!– IF n <= 1 THEN 1
• This suggests a recursive definition– Code:int factorial(int n) { if (n > 1) return(factorial(n-1)*n); return(1);}
• Notice conciseness
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
parameter
20
4
First Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
parameter
7
3Second Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
parameter
7
3Second Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n); 8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
parameter
7
2Third Call
1
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Function result
parameter1Fourth Call
7 Return address
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Function result
n1Fourth Call
7 Return address
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Function result
n1Fourth Call
7 Return address
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Function result
n1Fourth Call
7
1
Return address
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
1
7
1
2
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
7
2
1
7
1
2
6
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
7
3
7
2
1
7
1
2
6
24
Copyright © Curt Hill 2006-2007
Trace through it5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Function resultgiven to f
20
4
7
3
7
2
1
7
1
2
6
24
Copyright © Curt Hill 2006-2007
Which is better?
• Some would argue that the iterative version is more understandable
• Others would argue the opposite• The call overhead is more expensive
than the loop overhead• The recursive version will require
more memory and more time in most cases
Copyright © Curt Hill 2006-2007
Rules
• Rules for recursive functions• There must be at least one non-
recursive path through the routine– There may be many recursive or non-
recursive paths
• Each recursive path must move us toward a non-recursive path
Copyright © Curt Hill 2006-2007
Properties• Any recursive routine can be recoded non-
recursively• Any loop can be replaced by a recursive
routine• The loop is faster and takes less space• If that is the case why use recursion?
– Elegance– Easy to write
• Use recursion only for things inherently recursive– That is, if recursion simplifies the solution
Copyright © Curt Hill 2006-2007
Should We or Should We Not?
• There are many examples of routines that– Should be recursive– Could be recursive– Should not be recursive
• Factorial could be either but loop is preferred– Generally easier to code– Somewhat more efficient, but not
dramatically
Copyright © Curt Hill 2006-2007
Fibonacci• The Fibonacci sequence
– 1 1 2 3 5 8 13 21 34 55 89 ...– Number these from zero ==> F(6) = 13
• The definition is defined as follows:a0 = 1a1 = 1 an = an-1 + an-2
• As a function this becomes:int fib (int n){ if(n<2) return 1; return fib(n-1) + fib(n-2);}
• Is this better than the iterative one?
Copyright © Curt Hill 2006-2007
The Code
• Code:int fibo(int n){ if(n < 2) return 1; return fibo(n-1)+fibo(n-2);}
• What is wrong with this code?
Copyright © Curt Hill 2006-2007
Iterative Fibonacci• The iterative function:int fib2 (int n){ int first=1, second=1; int third = 1; while(--n>0){ third = first + second; first = second; second = third; } return third;}
Copyright © Curt Hill 2006-2007
So which of these is better
• The recursive is somewhat easier to read
• The iterative is much, much better from an execution point of view
• The recursive version re-computes what it has already computed– Several times
• Consider the following call graph
Copyright © Curt Hill 2006-2007
Fibonacci Call Graph
fib(6)
fib(4)
fib(2) fib(3)
fib(0) fib(1) fib(1) fib(2)
fib(5)
fib(3) fib(4)
fib(1) fib(2) fib(2) fib(3)
fib(0) fib(1) fib(0) fib(1)
fib(1) fib(2)fib(0)fib(1)
Copyright © Curt Hill 2006-2007
Fibonacci Discussion
• No re-using of calculated values• Fibo(2) is calculated twice • Fibonacci sequence should be
calculated from zero up• Using a loop
Copyright © Curt Hill 2006-2007
Tower of Hanoi• The legend:
– Buddhist monastery near Hanoi– 64 gold discs of descending size– Three pegs– Move the discs from one peg to another
• Rules– Only one disc can be moved at a time– A larger disk can not be put on a smaller– When they are all moved, world will end
• The solution is so inherently recursive that the loop solution is hard to see
Copyright © Curt Hill 2006-2007
Moving Process
• The moving process is inherently recursive
• There are two recursive calls– One before and one after the single
plate move
• The number of single plate moves is based on the plate number: 2N-1
• How many single plate moves to move a 64 plate stack?
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move the stack from A to B, using C as a temporary holder
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move 1 to C
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2 1
A B C
Move 2 to B
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move 1 to B
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 32
1
A B C
Move 3 to C
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 32
1
A B C
Move 1 to A
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 3
21
A B C
Move 2 to C
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 3
2
1
A B C
Move 1 to C
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 3
2
1
A B C
Move 4 to BThis is the halfway move.
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 3
21
A B C
Move 1 to B
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 32
1
A B C
Move 2 to A
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4 32
1
A B C
Move 1 to A
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move 3 to B
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2 1
A B C
Move 1 to C
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move 2 to B
Copyright © Curt Hill 2006-2007
Tower of Hanoi
4
3
2
1
A B C
Move 1 to BDone
Copyright © Curt Hill 2006-2007
Solution• To move Disk N from A to B using C:
– Move 1 to N-1 to C– Move N to B– Move 1 to N-1 to B
• Each move of multiple disks is recursive
• Two recursive calls per loop makes this more exciting
Copyright © Curt Hill 2006-2007
The codevoid move(int disk, char from, char to, char temp) {/* move disk from peg from to peg to using temp as temporary peg */if (1 < disk)
move(disk-1,from,temp,to);cout << "Move disk "<<disk <<" from "<<from << " to " << toif (1 < disk)
move(disk-1,temp,to,from);}
Copyright © Curt Hill 2006-2007
Recursive Loops
• Recursion is the generalization of looping
• Normal loops– The body of the loop is executed in a
straight line fashion– No opportunity to re-execute until end
• Recursive loops– Always start at the beginning and end at
end– A new loop can be inserted anywhere in
the loop
Copyright © Curt Hill 2006-2007
Discussion• Consider the following function:int recfun(int p1){ A; B; C; return …; }– Where A, B, C are arbitrary
sequences of statements• Where could recursive calls to
recfun be put and what would happen?
Copyright © Curt Hill 2006-2007
Before or After•Inserting the call before or
after the sequence gives the following sequence:–ABCABCABCABC
•Similar to a loop around the seqence
•This is what was used in factorial
•Called head or tail recursion
Copyright © Curt Hill 2006-2007
Head and Tail Recursion
• The factorial function is an example of tail recursion
• Tail recursion is when the routine does everything and then the recursive call last
• Head recursion is doing the call first• Usually head and tail recursion may
be easily converted to loops
Copyright © Curt Hill 2006-2007
One Call Elsewhere•Suppose the call is between A
and B•Then we get:
–AAABCBCBC•Still one recursive call•Now it will take two different
loops•However any one call can be
replaced by one or more loops
Copyright © Curt Hill 2006-2007
Two Calls • Suppose there is a call between A
and B and another between B and C• Twice through we would get
something like:– AABCBABCC
• Two recursive calls• How would you loop this?• Three times through:
– AAABCBABCCBAABCBABCCC– Although other orders are possible
• These two calls are similar to Hanoi
Copyright © Curt Hill 2006-2007
Maze Searching
• In maze searching the problem is that we often come to a fork in the road
• The looping solution must pursue one of these and save the other for future exploration
• The recursive solution goes both ways at once
• Like pouring water into the maze
Copyright © Curt Hill 2006-2007
Maze Searching
• Suppose we have a maze• How does one search a maze?• There are always multiple ways to go• Multiple paths may work
X
Copyright © Curt Hill 2006-2007
How do you do it?
• The solution is like pouring water into the maze
• If you will pour water into a 3D version of this it will move it all directions at once
• Make a recursive calls that advances one square– One recursive call for each possible
direction
Copyright © Curt Hill 2006-2007
Maze Representation• Assume a 25 by 25 array of
character– Maze may be smaller with a count– Positions 0 through count actually
constitute array• Getting to row or column 0 or row or
column count indicates success• Blanks are paths• Asterisks or other non-blanks are
obstacles• May only move up, down, left or right
Copyright © Curt Hill 2006-2007
Overview Algorithm• The search function will be a boolean
function– True indicate a path found
• Parameters are the position• If the position is not blank return
immediately• Replace position with ‘0’• If on edge return true• If any of the four ways from here
works replace with ‘= ’
Copyright © Curt Hill 2006-2007
Quick Sort
• Uses both looping and recursion– Just like we should use all types of loops
• The sort function has two distinct phases:
• Partition the array into three pieces– The upper part of array– An item– The lower part of array
• Recursively sort upper and lower part
Copyright © Curt Hill 2006-2007
Partitioning• Initialize
– Choose a pivot, typically the first array element
– Set an index to top and bottom values of remaining array
• Loop until indices collide– Find an element that is larger than
pivot in top– Find an element that is smaller than
pivot in bottom– Swap the two
• Move pivot to correct location
Copyright © Curt Hill 2006-2007
At the end of partition phase
• The array has three pieces:• All the elements smaller than the
pivot are together at the top• All the elements larger than the pivot
are together at the bottom• The pivot is between them and in its
sorted position– It will never be moved or looked at again
• Then recursively sort the two pieces
Copyright © Curt Hill 2006-2007
Quick Sort
83
19
14
26
Start, pivot is 8start looking
83
19
14
26
83
19
142
6
1st exch2nd exch
83
1
914
2
6
Pivot exch
23
1
914
8
6
Donefound
Three partitions
Copyright © Curt Hill 2006-2007
Efficiency
• Quick sort does well because of this partitioning
• 2 * (½ N)2 < N2
• Since the partitioning is repeatedly applied, it collapses to N log2N
• The partitioning fails if the pivot is the smallest or largest
• Degenerates to N2 for sorted or inversely sorted arrays
Copyright © Curt Hill 2006-2007
Determinants
• A determinant is a single number computed from a square matrix
• It is used in Cramer’s rule to find solutions to systems of equations
• It is a measure of goodness of the matrix of numbers
• It is also computed recursively
Copyright © Curt Hill 2006-2007
Computation
• Use the method of sums of values times the products of smaller determinants– Expanded minors
• Definition: A minor– A smaller matrix where one row and
column are eliminated
Copyright © Curt Hill 2006-2007
The minor of a 4 by 4• Suppose that we have the following:
4 2 1 -36 -2 7 -49 -7 8 -55 0 3 10
• The minor eliminating position 1,1 is:
4 1 -39 8 -55 3 10
Copyright © Curt Hill 2006-2007
Computing the Determinant
• The determinant of a 1 by 1 is just the value of that cell– This is the non-recursive version
• For a larger determinant:– Take each member of a row – Multiply that member times the
determinant of the minor with this row and column eliminated
– If the sum of subscripts of the member are even then add otherwise subtract
Copyright © Curt Hill 2006-2007
A Determinant of a two by two
326462
34
Copyright © Curt Hill 2006-2007
A Determinant of a three by three
51
335
79
334
79
512
795
514
332
Copyright © Curt Hill 2006-2007
Trees
• A tree is a dynamic data structure• A tree is:
– Empty– Node with one or more sub-trees
• The sub-trees could be empty
Copyright © Curt Hill 2006-2007
Tree Processing• Trees are always ordered• There are several linear routines in
processing a tree– Adding a node to a tree– Searching a tree
• The iterator is a different story • While finding all of the items it must
go both ways – a classic reason for a recursive routine
• This is a better topic for the next class
Copyright © Curt Hill 2006-2007
Common trees
• Binary search trees – used in memory
• BTrees – disk based search trees• Trie – A combination of tree and
array• Parse trees
Copyright © Curt Hill 2006-2007
Recursive Descent Parsing
• Consider this portion of a grammar
function: header compound stmt
compound stmt: { }stmt
stmt:
expression
if stmt
compound stmt
for stmt
Copyright © Curt Hill 2006-2007
The Parser• A recursive descent parser typically
has a function for each of the major constructs
• Thus for this language it would have:– Statement– Expression– CompoundStatement– IfStatement– ForStatement
• These would involve chains of recursive calls
Copyright © Curt Hill 2006-2007
Common Features
• The examples have this in common:• The recursive function often
generates more than one recursive call
• This makes it hard to generate an iterative solution
• However, there are one call functions that are hard to do iteratively as well
Copyright © Curt Hill 2006-2007
Languages
• Certain languages disallow recursion– FORTRAN– Older BASICs– COBOL
• Certain languages allow– The Pascal family– The C family
• Certain languages encourage– The LISP family
Copyright © Curt Hill 2006-2007
Automatic Variables
• Recursion is enabled by automatic variables
• Older versions of FORTRAN disallow recursion because it only had static variables
• Newer languages have automatic variables
• Each call of a function creates a separate copy of the parameters and local variables
• Recall the trace from before
Copyright © Curt Hill 2006-2007
Recall this trace5 int factorial(int n) { 6 if (n > 1) 7 return(factorial(n-1)*n);8 return(1);9 }...20 int f = factorial(4);
Return address
Function result
n
20
4
First Call
Return address
Function result
n
7
3Second Call
Return address
Function result
n
7
2Third Call
Function result
n1Fourth Call
7 Return address
Copyright © Curt Hill 2006-2007
Discussion
• In the previous trace there were four copies of n
• The ability to store local values is why recursion cannot be replaced by just looping
• Instead an auxiliary data structure• Recursion has that extra data
structure – the run-time stack
Copyright © Curt Hill 2006-2007
Converting Recursion to Looping
• The advantage that recursion has over looping is the storage of local variables and parameters on the stack
• In order to convert recursion to looping a secondary data structure is needed to hold the multiple processing opportunities
• Thus when the maze searcher wants to go four ways, it must save all four and then pick out one to pursue
• It is done when there is nothing left to check
Copyright © Curt Hill 2006-2007
Infinite Recursion
• Infinite recursion is similar to an infinite loop
• Just faster• What happens is that the stack space
is exhausted and rather quickly• What happens is that the recursive
paths to not move us closer to the non-recursive path
Copyright © Curt Hill 2006-2007
When to use Recursion
• When recursion is natural– The problem is inherently recursive– It should be easy to understand in this
situation
• No duplicate computation occurs• Iteration ends up being much more
complex– Needs an auxiliary data structure
• You are coding in LISP
Copyright © Curt Hill 2006-2007
Summary
• When it is easy always use looping• Looping can always be made faster• Recursion should be used when the
problem is inherently recursive• Properly used recursion will generally
be much more elegant than looping