Title: Recursion
1Recursion
2Big Picture
- Our objective is to write a recursive program and
convince ourselves it is correct with the minimum
amount of effort. - We will put some faith in the principles of
mathematical induction as we write the program - We will then check the program with a small,
non-trivial example - Anything that can be done with a loop, you can do
recursively, but its certainly not appropriate
in many cases. - Does it cause more or less work?
3What is recursion?
- Sometimes, the best way to solve a problem is by
solving a smaller version of the exact same
problem first - Recursion is a technique that solves a problem by
solving a smaller problem of the same type
4When you turn this into a program, you end up
with functions that call themselves (recursive
functions)
- int f(int x)
-
- int y
-
- if(x0)
- return 1
- else
- y 2 f(x-1)
- return y1
-
-
5All Odd Numbers are Prime
- How a physicist determines that all odd numbers
are prime - 3, 5, 7 are all prime, 9 experimental error,
11, 13 are prime they must all be prime - How a business major determines that all odd
numbers are prime - 3, 5, 7, 9, 11, are all prime they must all be
prime.
6The Danger With Testing
- It takes a long time to test a recursive program,
and its easy to make mistakes along the way - //This code doesnt work!!
- bool isPrime(int x)
- if (x 3)
- return true
-
- else if (isPrime(x-2))
- return true
- else
- return false
-
7Problems defined recursively
- There are many problems whose solution can be
defined recursively - Example n! (n factorial)
1 if n 0 n! (recursive
solution) (n-1)!n if n gt 0
1 if n 0 n! (closed form
solution) 123(n-1)n if n gt 0
8Coding the factorial function
- Recursive implementation
- int Factorial(int n)
-
- if (n0) // base case
- return 1
- else
- return n Factorial(n-1)
-
9(No Transcript)
10Coding the factorial function (cont.)
- Iterative implementation
- int Factorial(int n)
-
- int fact 1
-
- for(int count 2 count lt n count)
- fact fact count
-
- return fact
-
11Divide and Conquer
- Recursion works because mathematical induction
works. Have faith. Or. - Imagine that I have lots of very similar
functions - int fact(int n)
- if (n lt 2) return 1
- else return n fact2(n-1)
-
- int fact2(int n)
- if (n lt 2) return 1
- else return n fact3(n-1)
-
- // etc, etc.
12The Machine is Dumb
- The computer does not realize that the function
is calling itself! - The computer cannot distinguish between fact
calling fact, and fact calling fact2 - After all, the machine code for fact and the
machine code for fact2 are identical - So, if we could just become as dumb as the
computer, recursion would not be confusing.
13How is recursion implemented?
- What happens when a function gets called?
- int a(int w)
-
- return ww
-
-
- int b(int x)
-
- int z,y
- // other statements
- z a(x) y
-
- return z
-
14What happens when a function is called? (cont.)
- An activation record is stored into a stack
(run-time stack) - The computer has to stop executing function b and
starts executing function a - Since it needs to come back to function b later,
it needs to store everything about function b
that is going to need (x, y, z, and the place to
start executing upon return) - Then, x from a is bounded to w from b
- Control is transferred to function a
15What happens when a function is called? (cont.)
- After function a is executed, the activation
record is popped out of the run-time stack - All the old values of the parameters and
variables in function b are restored and the
return value of function a replaces a(x) in the
assignment statement
16What happens when a recursive function is called?
- Except the fact that the calling and called
functions have the same name, there is really no
difference between recursive and nonrecursive
calls - int f(int x)
-
- int y
-
- if(x0)
- return 1
- else
- y 2 f(x-1)
- return y1
-
-
172f(2)
2f(1)
2f(1)
f(0)
f(1)
f(2)
f(3)
18Another example n choose k (combinations)
- Given n things, how many different sets of size k
can be chosen? - n n-1 n-1
- , 1 lt k lt n (recursive solution)
- k k k-1
- n n!
- , 1 lt k lt n (closed-form solution)
- k k!(n-k)!
- with base cases
- n n
- n (k 1), 1 (k n)
- 1 n
19n choose k (combinations)
- int Combinations(int n, int k)
-
- if(k 1) // base case 1
- return n
- else if (n k) // base case 2
- return 1
- else
- return(Combinations(n-1, k)
Combinations(n-1, k-1)) -
20(No Transcript)
21Recursion vs. iteration
- Iteration can be used in place of recursion
- An iterative algorithm uses a looping construct
- A recursive algorithm uses a branching structure
- Recursive solutions are often less efficient, in
terms of both time and space, than iterative
solutions - Recursion can simplify the solution of a problem,
often resulting in shorter, more easily
understood source code
22Termination, Stack Depth and Efficiency
- We should always check to ensure our recursive
programs terminate. - We should avoid programs that have lots of
activation records on the stack at the same time
(the stack depth) - The time required for most recursive programs is
proportional to the number of recursive calls
23How do I write a recursive function?
- Determine the size factor
- Determine the base case(s)
- (the one for which you know the answer)
- Determine the general case(s)
- (the one where the problem is expressed as a
smaller version of itself) - Verify the algorithm
- (use the "Three-Question-Method")
24Three-Question Verification Method
- The Base-Case Question
- Is there a nonrecursive way out of the function,
and does the routine work correctly for this
"base" case? - The Smaller-Caller Question
- Does each recursive call to the function involve
a smaller case of the original problem, leading
inescapably to the base case? - The General-Case Question
- Assuming that the recursive call(s) work
correctly, does the whole function work
correctly?
25Step 1 Identify Your Base Case
- A base case is an input value (or set of values)
for which - Determining the result of our function is
trivially easy - All other values can ultimately be reduced to
(one of) our base case(s) through a finite
sequence of decompositions
26Base Case Examples
- Factorial and Fibonacci n lt 2
- Sorting n lt 2 (either array has 1 element or it
has no elements at all) - Towers of Hanoi n 1 (exactly one ring)
- Making Change The amount of change is exactly
the same monetary value as a single coin
27Step 2 Pick a Decomposition
- It may take us a couple of tries to get the
decomposition right, but we have to start
somewhere - The decomposition must
- Reduce the problem to a smaller problem
- Result in eventually reaching the base case
- Somehow be useful to solving the original problem
28Example Decompositions
- Subtract one from n (and compute n-1 factorial)
- Divide the array in half (and sort each half)
- Skip the first number (and compute the mean of
the remaining elements)???
29Recursive binary search
- Non-recursive implementation
- templateltclass ItemTypegt
- void SortedTypeltItemTypegtRetrieveItem(ItemType
item, bool found) -
- int midPoint
- int first 0
- int last length - 1
-
- found false
- while( (first lt last) !found)
- midPoint (first last) / 2
- if (item lt infomidPoint)
- last midPoint - 1
- else if(item gt infomidPoint)
- first midPoint 1
- else
- found true
- item infomidPoint
30Recursive binary search (contd)
- What is the size factor?
- The number of elements in (infofirst ...
infolast) - What is the base case(s)?
- (1) If first gt last, return false
- (2) If iteminfomidPoint, return true
- What is the general case?
- if item lt infomidPoint search the first half
- if item gt infomidPoint, search the second half
31Recursive binary search (contd)
- templateltclass ItemTypegt
- bool BinarySearch(ItemType info, ItemType
item, int first, int last) -
- int midPoint
-
- if(first gt last) // base case 1
- return false
- else
- midPoint (first last)/2
- if(item lt infomidPoint)
- return BinarySearch(info, item, first,
midPoint-1) - else if (item infomidPoint) // base
case 2 - item infomidPoint
- return true
-
- else
- return BinarySearch(info, item,
midPoint1, last) -
-
32Recursive binary search (contd)
- templateltclass ItemTypegt
- void SortedTypeltItemTypegtRetrieveItem
(ItemType item, bool found) -
- found BinarySearch(info, item, 0,
length-1)
33Recursive InsertItem (sorted list)
location
location
location
location
34Recursive InsertItem (sorted list)
- What is the size factor?
- The number of elements in the current list
- What is the base case(s)?
- If the list is empty, insert item into the empty
list - If item lt location-gtinfo, insert item as the
first node in the current list - What is the general case?
- Insert(location-gtnext, item)
35Recursive InsertItem (sorted list)
- template ltclass ItemTypegt
- void Insert(NodeTypeltItemTypegt location,
ItemType item) -
- if(location NULL) (item lt
location-gtinfo)) // base cases -
- NodeTypeltItemTypegt tempPtr location
- location new NodeTypeltItemTypegt
- location-gtinfo item
- location-gtnext tempPtr
-
- else
- Insert(location-gtnext, newItem) //
general case -
-
- template ltclass ItemTypegt
- void SortedTypeltItemTypegtInsertItem(ItemType
newItem) -
- Insert(listData, newItem)
-
36- No "predLoc" pointer is needed for insertion
location
37Recursive DeleteItem (sorted list)
location
location
38Recursive DeleteItem (sorted list) (cont.)
- What is the size factor?
- The number of elements in the list
- What is the base case(s)?
- If item location-gtinfo, delete node pointed
by location - What is the general case?
- Delete(location-gtnext, item)
39Recursive DeleteItem (sorted list) (cont.)
- template ltclass ItemTypegt
- void Delete(NodeTypeltItemTypegt location,
ItemType item) -
- if(item location-gtinfo))
-
- NodeTypeltItemTypegt tempPtr location
- location location-gtnext
- delete tempPtr
-
- else
- Delete(location-gtnext, item)
-
-
- template ltclass ItemTypegt
- void SortedTypeltItemTypegtDeleteItem(ItemType
item) -
- Delete(listData, item)
-
40Recursion can be very inefficient is some cases
15
41Deciding whether to use a recursive solution
- When the depth of recursive calls is relatively
"shallow" - The recursive version does about the same amount
of work as the nonrecursive version - The recursive version is shorter and simpler than
the nonrecursive solution