Recursion - PowerPoint PPT Presentation

1 / 51
About This Presentation
Title:

Recursion

Description:

Title: Ch8:Recursion Last modified by: Jason Ding Created Date: 5/28/1995 4:12:40 PM Document presentation format: On-screen Show (4:3) Other titles – PowerPoint PPT presentation

Number of Views:141
Avg rating:3.0/5.0
Slides: 52
Provided by: csGsuEdu51
Category:

less

Transcript and Presenter's Notes

Title: Recursion


1
Chapter 8
  • Recursion

2
Objective
  • To learn
  • What is recursion?
  • Proof by induction
  • Basic recursion
  • Numerical Applications
  • Divide and Conquer

3
Introduction to Recursion
  • "Normally", we have methods that call other
    methods.
  • For example, the main() method calls the square()
    method.
  • Recursive Method
  • A recursive method is a method that calls itself.

main()
square()
compute()
ref cs.nyu.edu/courses/fall07/V22.0102-002/lectur
es/recursion-102-fa07.ppt
4
Why use Recursive Methods?
  • In computer science, some problems are more
    easily solved by using recursive methods.
  • In this course, will see many of examples of
    this.
  • For example
  • Traversing through a directory or file system.
  • Traversing through a tree of search results.
  • Some sorting algorithms recursively sort data
  • For today, we will focus on the basic structure
    of using recursive methods.

5
Worlds Simplest Recursion Program
  • include ltiostreamgt
  • using namespace std
  • void count (int index)
  • cout ltlt index
  • if (index lt 2)
  • count(index1)
  • int main ()
  • count(0)
  • cout ltlt endl
  • return 0

This program simply counts from 0-2 012
This is where the recursion occurs. You can see
that the count() method calls itself.
6
Visualizing Recursion
  • To understand how recursion works, it helps to
    visualize whats going on.
  • To help visualize, we will use a common concept
    called the Stack.
  • A stack basically operates like a container of
    trays in a cafeteria. It has only two
    operations
  • Push you can push something onto the stack.
  • Pop you can pop something off the top of the
    stack.
  • Lets see an example stack in action.

7
Stacks
The diagram below shows a stack over time. We
perform two pushes and one pop.
8
2
2
2
Time 0 Empty Stack
Time 1 Push 2
Time 2 Push 8
Time 3 Pop Gets 8
Time 4 Pop Gets 2
8
Stacks and Methods
  • When you run a program, the computer creates a
    stack for you.
  • Each time you invoke a method, the method is
    placed on top of the stack.
  • When the method returns or exits, the method is
    popped off the stack.

9
Stacks and Methods
square()
main()
main()
main()
Time 4 Pop main() returns a value. method
exits.
Time 3 Pop square() returns a value. method
exits.
Time 0 Empty Stack
Time 1 Push main()
Time 2 Push square()
This is called an activation record or stack
frame. Usually, this actually grows downward.
10
Stacks and Recursion
  • Each time a method is called, you push the method
    on the stack.
  • Each time the method returns or exits, you pop
    the method off the stack.
  • If a method calls itself recursively, you just
    push another copy of the method onto the stack.
  • We therefore have a simple way to visualize how
    recursion really works.

11
Back to the Simple Recursion Program
  • Heres the code again. Now, that we understand
    stacks, we can visualize the recursion.
  • include ltiostreamgt
  • using namespace std // Recursion1V0
  • void count (int index)
  • cout ltlt index
  • if (index lt 2)
  • count(index1)
  • int main ()
  • count(0)
  • cout ltlt endl
  • return 0

12
Stacks and Recursion in Action
count(2)
count(1)
count(1)
count(0)
count(0)
count(0)

main()
main()
main()
main()
Time 0 Empty Stack
Time 1 Push main()
Time 2 Push count(0)
Time 3 Push count(1)
Time 4 Push count(2)
Times 5-8 Pop everything
Inside count(0) cout ltltindex ? 0 if
(index lt 2) count(index1)
Inside count(1) cout ltltindex ? 1 if (index
lt 2) count(index1)
Inside count(2) cout ltltindex ? 2 if (index lt
2) count(index1) This condition now
fails! Hence, recursion stops, and we proceed to
pop all methods off the stack.
13
Recursion, Variation 1
  • What will the following program do?
  • include ltiostreamgt
  • using namespace std // Recursion1V1
  • void count (int index)
  • cout ltlt index
  • if (index lt 2)
  • count(index1)
  • int main ()
  • count(3)
  • cout ltlt endl
  • return 0

14
Recursion, Variation 2
  • What will the following program do?
  • include ltiostreamgt
  • using namespace std // Recursion1V0
  • void count (int index)
  • if (index lt 2)
  • count(index1)
  • cout ltlt index
  • int main ()
  • count(0)
  • cout ltlt endl
  • return 0

Note that the print statement has been moved to
the end of the method.
15
Recursion, Variation 3
  • What will the following program do?
  • include ltiostreamgt
  • using namespace std // Recursion1V0
  • void count (int index)
  • if (index gt 2)
  • count(index1)
  • cout ltlt index
  • int main ()
  • count(3)
  • cout ltlt endl
  • return 0

16
First two rules of recursion
  • Base case You must always have some base case
    which can be solved without recursion
  • Making Progress For cases that are to be solved
    recursively, the recursive call must always be a
    case that makes progress toward the base case.

From Data Structures and Algorithms by Mark Allen
Weiss
17
Problem Not working towards base case
  • In variation 3, we do not work towards our base
    case. This causes infinite recursion and will
    cause our program to crash.

18
Factorials
  • Computing factorials are a classic problem for
    examining recursion.
  • A factorial is defined as follows
  • n! n (n-1) (n-2) . 1
  • For example
  • 1! 1
  • 2! 2 1 2
  • 3! 3 2 1 6
  • 4! 4 3 2 1 24
  • 5! 5 4 3 2 1 120

If you study this table closely, you will start
to see a pattern.
19
Seeing the Pattern
  • Seeing the pattern in the factorial example is
    difficult at first.
  • But, once you see the pattern, you can apply this
    pattern to create a recursive solution to the
    problem.
  • Divide a problem up into
  • What we know (call this the base case)
  • Making progress towards the base
  • Each step resembles original problem
  • The method launches a new copy of itself
    (recursion step) to make the progress.

20
Factorials
  • Computing factorials are a classic problem for
    examining recursion.
  • A factorial is defined as follows
  • n! n (n-1) (n-2) . 1
  • For example
  • 1! 1 (Base Case)
  • 2! 2 1 2
  • 3! 3 2 1 6
  • 4! 4 3 2 1 24
  • 5! 5 4 3 2 1 120

If you study this table closely, you will start
to see a pattern. The pattern is as follows You
can compute the factorial of any number (n) by
taking n and multiplying it by the factorial of
(n-1). For example 5! 5 4! (which
translates to 5! 5 24 120)
21
Recursive Solution
Base Case.
  • int findFactorial (int number)
  • if ( number lt1)
  • return 1
  • else
  • return (number findFactorial (number-1))
  • int main ()
  • for (int i 1 i lt 10 i)
  • cout ltlt i ltlt "! " ltlt findFactorial(i) ltlt
    endl
  • return 0

Making progress
22
Finding the factorial of 3
fact(1)
1
fact(2)
fact(2)
fact(2)
2
fact(3)
fact(3)
fact(3)
fact(3)
fact(3)
6
main()
main()
main()
main()
main()
main()
Time 3 Push fact(2)
Time 4 Push fact(1)
Time 7 Pop fact(3) returns 6.
Time 2 Push fact(3)
Time 6 Pop fact(2) returns 2.
Time 5 Pop fact(1) returns 1.
Inside findFactorial(1) if (number lt 1) return
1 else return (1 factorial (0))
Inside findFactorial(3) if (number lt 1) return
1 else return (3 factorial (2))
Inside findFactorial(2) if (number lt 1) return
1 else return (2 factorial (1))
23
Tail recursion
  • Tail recursion is when the last line of a method
    makes the recursive call.
  • In this case, you have multiple active stack
    frames which are unnecessary because they have
    finished their work.
  • It is easy to rid you program of this type of
    recursion. These two steps will do so
  • Enclose the body of the method in a while loop
  • Replace the recursive call with an assignment
    statement for each method argument.
  • Most compilers do this for you. Note I said
    "most".

24
Revisit recursive factorial solution
Just follow our two steps
int findFactorial (int number) if
(numberlt1) return 1 else
return (number findFactorial
(number-1)) int main () for (int i
1 i lt 10 i) cout ltlt i ltlt "! " ltlt
findFactorial(i) ltlt endl return 0
int findFactorial (int number) int answer
1 while ( number gt 1) answer
answer number number --
return answer int main () for
(int i 1 i lt 10 i) cout ltlt i ltlt "! "
ltlt findFactorial(i) ltlt endl return 0
25
Recursive Function Call
  • A recursion function is a function that either
    directly or indirectly makes a call to itself.
  • But, we need to avoid making an infinite sequence
    of function calls (infinite recursion).
  • A recursive solution to a problem must be written
    carefully
  • The idea is for each successive recursive call to
    bring you one step closer to a situation in which
    the problem can easily be solved
  • This easily solved situation is called the base
    case
  • Each recursive algorithm must have at least one
    base case, as well as a general (recursive) case

26
Mathematical Induction
  • To prove

Let p(n) denote the statement involving the
integer variable n. The Principle of
Mathematical Induction states If p(1) is true
and, for some integer K gt1 , p(k1) is
true whenever p(k) is true then p(n) is
true for all ngt1 .
27
A recursive definition
  • int s (int n)
  • if (n 1)
  • return 1
  • else
  • return s(n-1) n

28
Printing number in 10 Base
  • void printDecimal (int n)
  • if (ngt10)
  • printDecimal(n/10)
  • cout.put(0n10)

29
Printing number in Any Base
  • const string DIGIT_TABLE "0123456789abcdef"
  • const int MAX_BASE DIGIT_TABLE.length( )
  • void printIntRec( int n, int base )
  • if( n gt base )
  • printIntRec( n / base, base )
  • cout ltlt DIGIT_TABLE n base

30
General format for Many Recursive Functions
  • if (some easily-solved condition) // base
    case
  • solution statement
  • else // general case
  • recursive function call

31
When a function is called...
  • A transfer of control occurs from the calling
    block to the code of the function--it is
    necessary that there be a return to the correct
    place in the calling block after the function
    code is executed this correct place is called
    the return address
  • When any function is called, the run-time stack
    is used on this stack is placed an activation
    record for the function call

32
Stack Activation Frames
  • The activation record contains the return address
    for this function call, and also the parameters,
    and local variables, and space for the functions
    return value, if non-void
  • The activation record for a particular function
    call is popped off the run-time stack when the
    final closing brace in the function code is
    reached, or when a return statement is reached in
    the function code
  • At this time the functions return value, if
    non-void, is brought back to the calling block
    return address for use there

33
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
FCTVAL
? result
? b 2
a 5 Return
Address 100
original call at instruction 100 pushes on this
record for Func(5,2)
34
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
FCTVAL ?
result ?
b 1
a 5 Return Address 50
FCTVAL ?
result 5Func(5,1) ?
b 2 a
5 Return Address 100
call in Func(5,2) code at instruction 50 pushes
on this record for Func(5,1)
35
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
call in Func(5,1) code at instruction 50 pushes
on this record for Func(5,0)
FCTVAL ?
result ?
b 0 a
5 Return Address 50
FCTVAL ?
result 5Func(5,0) ?
b 1 a
5 Return Address 100
FCTVAL ?
result 5Func(5,1) ?
b 2 a
5 Return Address 100
36
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
FCTVAL 0
result 0
b 0 a
5 Return Address 50
FCTVAL ?
result 5Func(5,0) ?
b 1 a
5 Return Address 50
FCTVAL ?
result 5Func(5,1) ?
b 2 a
5 Return Address 100
record for Func(5,0) is popped first with its
FCTVAL
record for Func(5,1)
record for Func(5,2)
37
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
FCTVAL 5
result 5Func(5,0) 5 0
b 1
a 5 Return Address
100 FCTVAL
? result 5Func(5,1) ?
b 2
a 5 Return Address
100
record for Func(5,1) is popped next with its
FCTVAL
record for Func(5,2)
38
Run-Time Stack Activation Records x Func(5,
2) // original call at instruction 100
FCTVAL
10 result 5Func(5,1)
55 b 2
a 5 Return
Address 100
record for Func(5,2) is popped last with its
FCTVAL
39
Too much recursion Can Be Dangerous
Fibonacci numbers. Long fib (int n) If (n
lt1) return n Else return
fib(n-1) fib(n-2) This definition will lead
to exponential running time.
40
Tree
  • Tree is a fundamental structure in computer
    science.
  • Recursive definition A tree is a root and zero
    or more nonempty subtrees.
  • Nonrecursive definition A connected graph
    without loop.

41
Some more examples
  • Binary Search
  • template ltclass Comparablegt int binarySearch(
    const vectorltComparablegt a, const Comparable
    x, int low, int high )
  • if( low gt high )
  • return NOT_FOUND
  • int mid ( low high ) / 2
  • if( a mid lt x )
  • return binarySearch( a, x, mid 1,
    high )
  • else if( x lt a mid )
  • return binarySearch( a, x, low, mid
    - 1 )
  • else return mid

42
Numerical Applications
  • Modular exponentiation Compute XN(mod P)
  • Greatest common divisor Compute gcd(A, B)

43
Modular exponentiation
  • Three rules
  • If AB (mod N), then for any C, AC BC (mod N)
  • If AB (mod N), then for any D, AD BD (mod N)
  • If AB (mod N), then for any positive P, APBP
    (mod N)

44
Continue
  • If N is even, XN (XX)N/2
  • If N is odd, XN X(XX)N/2
  • template ltclass HugeIntgt HugeInt power( const
    HugeInt x, const HugeInt n , const HugeInt
    p )
  • if( n 0 )
  • return 1
  • HugeInt tmp power( ( x x ) p, n / 2,
    p )
  • if( n 2 ! 0 )
  • tmp ( tmp x ) p
  • return tmp

45
Greatest common divisor
  • One rule
  • gcd(A, B) gcd(A-B, B) or gcd(B, A mod B)
  • Example
  • gcd(71, 25)?gcd(25, 21) ?gcd(21, 4) ?gcd(4, 1)
    ?gcd(1, 0) 1
  • template ltclass HugeIntgt
  • HugeInt gcd( const HugeInt a, const HugeInt
    b)
  • if (b 0)
  • return a
  • else
  • return gcd(b, ab)

46
Divide and Conquer
  • Given an instance of the problem to be solved,
    split this into several, smaller, sub-instances
    (of the same problem) independently solve each of
    the sub-instances and then combine the
    sub-instance solutions so as to yield a solution
    for the original instance.

47
The Maximum Contiguous Subsequence Sum Problem
Consider 4, -3, 5, -2, -1, 2, 6, -2 Case 1 It
resides entirely in the first half. Case 2 It
resides entirely in the second half. Case 3 It
begins in the first half but ends in the
second half.
48
  • template ltclass Comparablegt Comparable
    maxSubSum( const vectorltComparablegt a, int
    left, int right )
  • Comparable maxLeftBorderSum 0,
    maxRightBorderSum 0
  • Comparable leftBorderSum 0, rightBorderSum
    0
  • int center ( left right ) / 2
  • if( left right ) // Base Case.
  • return a left gt 0 ? a left
    0
  • Comparable maxLeftSum maxSubSum( a, left,
    center )
  • Comparable maxRightSum maxSubSum( a,
    center 1, right )
  • for( int i center i gt left i-- )
  • leftBorderSum a i
  • if( leftBorderSum gt maxLeftBorderSum
    )
  • maxLeftBorderSum
    leftBorderSum
  • for( int j center 1 j lt right j )
  • rightBorderSum a j
  • if( rightBorderSum gt
    maxRightBorderSum )
  • maxRightBorderSum
    rightBorderSum

49
Analysis of Divide and Conquer Recurrence
  • T(N) 2T(N/2) O(N)
  • Result
  • T(N)/N T(1)/1 logN

50
Common Errors
  • Forgetting a base case
  • Overlapping recursive calls
  • Using recursion in place of a simple loop.

51
Homework
  • Question
  • 8.27, due next Wed. (Feb. 11)
  • Print your program
  • Finish reading chapter 8
Write a Comment
User Comments (0)
About PowerShow.com