Recursion - PowerPoint PPT Presentation

1 / 60
About This Presentation
Title:

Recursion

Description:

CHAPTER TWO 2 - Nipissing University ... Recursion * – PowerPoint PPT presentation

Number of Views:112
Avg rating:3.0/5.0
Slides: 61
Provided by: niroomand
Category:

less

Transcript and Presenter's Notes

Title: Recursion


1
Lecture 2
  • Recursion

2
CHAPTER TWO
  • Recursion A recursive function is a function
    that calls itself.
  • Two functions A and B are mutually recursive, if
    A calls B and B calls A.Recursion can always
    replace iteration (looping).
  • n!
  • A simple example Factorial.
  • Factorial(0) 1 (By definition)
  • Factorial(1) 1
  • Factorial(2) 21
  • Factorial(3) 321
  • Factorial(4) 4321
  • Factorial(5) 54321
  • Factorial(n) n n-1 n-2 ... 1

3
DEFINITION OF n!
  • 1 if n 0
  • Factorial(n)
  • n Factorial(n-1) if n gt 0
  • This recursive definition needs for a recursive
    implementation.

4
Recursive implementation
  • int factorial (int n)
  • if (n 0)
  • return 1
  • else
  • return n factorial(n - 1)

5
How to understand recursion
  • Every time a recursive function is called, thats
    like it is a completely separate function.
  • Just ignore the fact that this function was
    called by itself.
  • Specifically, if factorial calls itself, then
    there are two parameters n that have NOTHING to
    do with each other.

6
EXAMPLE factorial(3)
  • factorial(3) n 3 calls factorial(2)
  • factorial(2) n 2 calls factorial(1)
  • factorial(1) n 1 calls factorial(0)
  • factorial(0) returns 1 to factorial(1).
    Inside factorial(1),
  • 1 factorial(0) becomes 1 1
  • factorial(1) returns 1 to factorial(2),
  • Inside factorial(2), 2 factorial(1) becomes 2
    1

7
EXAMPLE factorial(3) CONTINUED
  • factorial(2) returns 2 to factorial(3).
  • Inside factorial(3), 3 factorial(2) becomes 3
    2
  • So, inside factorial(3), the return value is 3
    2 6. This is what will be returned to the
    program.
  • cout ltlt factorial(3) // writes 6 to the screen.

8
What problems can be recursively solved?
  • The following conditions should be fulfilled
  • 1 - The problem can be decomposed into several
    problems such that (at least) one of them is of
    the same kind as the initial problem but
    simpler and all the others are easy and
  • 2 - If you keep deriving simpler and simpler
    problems of the same kind, you will eventually
    reach an easy problem.

9
Why factorial () can be recursive?
  • 1 - factorial(n) is decomposed into two problems
  • A multiplication and factorial(n-1) is a problem
    of
  • the same kind as factorial(n), but factorial(n-1)
    is
  • Also simpler than factorial(n).
  • 1)factorial(n) n factorial(n - 1) --- if n gt
    0
  • 2)factorial(n) 1 --- if n 0
  • 2 - If we keep reducing the argument of
    factorial( )
  • more and more, eventually, we will get
    factorial(0)
  • which is easy to solve.

10
Factorial Illustration

cout ltlt Fact(3)
6
Return 3Fact(2) 32
Return 2Fact(1) 21
int Fact(int N) if (N 0) return 1
else return N Fact(N-1)
Return 1Fact(0) 11
Return 1
Fact(3)
11
Factorial Illustration contd
N 3 A Fact(N-1) ? Return ?

N 2 A Fact(N-1) ? Return ?
N 3 A Fact(N-1) ? Return ?
N 1 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) ? Return ?
N 3 A Fact(N-1) ? Return ?
N 0 Return ?
N 1 A Fact(N-1) ? Return ?
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) ? Return ?
N 0 Return 1
N 1 A Fact(N-1) ? Return ?
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) ? Return ?
N 0 Return 1
N 1 A Fact(N-1) 1 Return ?
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) ? Return ?
12
Factorial Illustration contd
N 0 Return 1
N 1 A Fact(N-1) 1 Return 1
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) ? Return ?

N 0 Return 1
N 1 A Fact(N-1) 1 Return 1
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) 1 Return ?
N 0 Return 1
N 1 A Fact(N-1) 1 Return 1
N 3 A Fact(N-1) ? Return ?
N 2 A Fact(N-1) 1 Return 2
N 0 Return 1
N 1 A Fact(N-1) 1 Return 1
N 3 A Fact(N-1) 2 Return ?
N 2 A Fact(N-1) 1 Return 2
N 0 Return 1
N 1 A Fact(N-1) 1 Return 1
N 3 A Fact(N-1) 2 Return 6
N 2 A Fact(N-1) 1 Return 2
13
Example Writing an array backwards
  • Given an array of characters, and we want to
    write its elements backwards to the screen, i.e.,
    starting with the last character.
  • Of course this can be done with a
  • for (x ArraySize-1 x gt 0 --x) loop, but we
    will do it recursively.
  • Lets try to decompose the problem.

14
Decomposition
  • 1 - Writing an array of length n can be
    decomposed into writing a single character
    (thats easy) and writing an array of length
    n-1 backwards, which is a problem of the same
    kind as writing an array of length n, but its
    simpler.
  • 2 - If we keep reducing the length of the array
    that we have to write backwards, we will
    eventually end up with an array of size 1. That
    is a character, and writing a character is
    easy.
  • EVEN BETTER, we can go to an array of size ZERO
    and then we have to do NOTHING.

15
Write the function
  • Still, nothing in this description results in
    something written
  • backward! We refine
  • An array is written backward by FIRST writing its
    last
  • element, and then writing the array that is left
    backwards. If
  • we come down to an array of size 0, we do
    nothing.
  • void writebackward(char S, int size)
  • if (size gt 0)
  • cout ltlt Ssize-1
  • writebackward(S, size-1)

16
Execute the function
  • Lets trace through this with the following
  • example
  • Assume that ST contains the characters C A T.
  • writebackward(ST, 3) is now called.
  • Within writebackward( ) we have therefore

ST
A
T
3
C
17
Step by step
  • cout ltlt S3-1 will send to the screen T
  • Then comes the recursive call to
  • writebackward(S,2)
  • Note that S is never changed in the process.
  • writebackward(S,2) will first do
  • cout ltlt S2-1 which will write to screen A
  • Then comes the recursive call to
  • writebackward(S,1)
  • writebackward(S,1) will first do
  • cout ltlt S1-1 which will write to screen C
  • Then comes the recursive call to

18
Last step
  • writebackward(S,0)
  • Writebackward(S,0) will do NOTHING.
  • Note that we have already written TAC to the
    screen.
  • Note that the program does not end here.
  • Take a look back at the code of
  • writebackward( ).
  • You see that NOTHING is done in
  • writebackward( ) AFTER the recursive call.

19
writebackward( ) Return Path
  • writebackward(S,0) returns to
    writebackward(S,1)
  • writebackward(S,1) has nothing left to do,
  • returns to its caller, writebackward(S,2).
  • writebackward(S,2) has nothing left to do,
  • returns to its caller, writebackward(S,3).
  • When writebackward(S,3) returns, the program
  • is finished.

20
WriteBackWard(S, size) 20
S cat Size 3
S cat Size 2
S cat Size 3
S cat Size 1
S cat Size 2
S cat Size 3
S cat Size 0
S cat Size 1
S cat Size 2
S cat Size 3
S cat Size 0
S cat Size 1
S cat Size 2
S cat Size 3
S cat Size 0
S cat Size 1
S cat Size 2
S cat Size 3
S cat Size 0
S cat Size 1
S cat Size 2
S cat Size 3
21
Another solution
  • Another solution to the writeback problem
  • void writeback(char S, int size, int pos)
  • if (pos lt size)
  • writeback(S, size, pos1)
  • cout ltlt Spos

22
Initial call
  • We need to call this as follows
  • Assume again that ST contains the characters
  • C A T
  • writeback(ST, 3, 0)
  • Note that this procedure does SOMETHING
  • after the recursive call. This is harder.

23
Nothing happens at the beginning
  • Inside of writeback(ST, 3, 0) nothing happens
  • before the recursive call. The recursive call
  • will be
  • writeback(S, 3, 1)

24
Nothing
  • Inside of writeback(S, 3, 1) nothing happens
  • before the recursive call. The recursive call
  • will be writeback(S, 3, 2).
  • Inside of writeback(S, 3, 2) nothing happens
  • before the recursive call. The recursive call
  • will be writeback(S, 3, 3).

25
writeback( ) Return Path
  • writeback(S, 3, 3) will not do anything,
    because
  • the IF condition evaluates to FALSE.
  • writeback(S, 3, 3) returns to writeback(S, 3,
    2).
  • writeback(S, 3, 2) sends T to the screen.
  • writeback(S, 3, 2) returns to writeback(S, 3,
    1).
  • writeback(S, 3, 1) sends A to the screen.
  • writeback(S, 3, 1) returns to writeback(S, 3,
    0).
  • writeback(S, 3, 0) sends C to the screen.
  • writeback(S, 3, 0) returns to the main program.

26
WriteBackWard(S)
WriteBackWard(S)
WriteBackWard(S minus last character)
void WriteBackWard(char S) cout ltlt"Enter
WriteBackWard with string " ltlt S ltlt endl if
(strlen(S)0) else cout ltlt "About to write
last character of string" ltlt S ltlt endl cout
ltltSstrlen(S)-1ltltendl Sstrlen(S)-1'\0'
WriteBackWard(S) cout ltlt "Leave
WriteBackWard with string" ltlt S ltlt endl
27
WriteBackWard(S)
S cat
S ca
S cat
S c
S ca
S cat
S
S c
S ca
S cat
S
S c
S ca
S cat
S
S c
S ca
S cat
S
S c
S ca
S cat
28
WriteBackWard(S)
Output stream Enter WriteBackWard with string
cat About to write last character of string
cat t Enter WriteBackWard with string ca About
to write last character of string ca a Enter
WriteBackWard with string c About to write last
character of string c C Enter WriteBackWard with
string About to write last character of
string Leave WriteBackWard with string Leave
WriteBackWard with string c Leave WriteBackWard
with string ca Leave WriteBackWard with string
cat
29
POWER
  • Xn 1 IF n 0 Base Case
  • Xn XX(n-1) IF n gt 0 Recursive Case
  • This can be translated easily into C.
  • However, we can do better
  • Xn 1 IF n 0
  • Xn X square of X(n / 2) IF n is odd
  • Xn square of X(n / 2) IF n is even

30
The function
  • int power(int X, int N)
  • if (N 0)
  • return 1
  • else
  • int HalfPower power(X, N/2)
  • if (N 2 0)
  • return HalfPower HalfPower // Even n
  • else
  • return X HalfPower HalfPower // Odd n

31
FIBONACCI SEQUENCE
  • A sequence of numbers is defined as follows
  • The first number is 1. The second number is 1.
  • Every other number is the sum of the two
  • numbers before it.
  • 1 1 2 3 5 8 13 21 34 55 89
  • fib(1) 1 Base Case
  • fib(2) 1 Base Case
  • fib(n) fib(n-1) fib(n-2) n gt 2
  • This is a recursion that uses TWO base cases, and
    it breaks down a problem into TWO simpler
    problems of the same kind.

32
The Function
  • int fib(int n)
  • if (n lt 2)
  • return 1
  • else
  • return fib(n-1) fib(n-2)
  • The recursive implementation is, however,
    TERRIBLY inefficient, and is not recommended.
  • fib(7) will call fib(3) 5 times! What a waste!

33
An (artificial) example with rabbits.
  • - Rabbits never die.
  • - Rabbits always give birth to twins, male and
    female.
  • - A couple of rabbits give birth to twins at the
    first day of every month, starting at age 3
    months.
  • - We start with ADAM rabbit and EVE Rabbit.

34
The couples of rabbits are Fibonacci numbers
  • Month 1 Couples1 Adam, Eve
  • 2 1 Adam, Eve
  • 3 2 AE and twins 1
  • 4 3 AE twins 1, twins 2
  • 5 5 AE, twins 1, twins 2
    twins 3 (from AE) and twins 4 (from
    twins 1)
  • 6 8 AE, twins 1-4
  • twins 5 (from AE), twins 6 (from 1),
    twins 7 (from 2)
  • Surprise!? These are the Fibonacci numbers.

35
The Mad Scientists Problem
  • We want to make a chain out of pieces of Lead and
    Plutonium.
  • The chain is supposed to be of length n.
  • However, there is a problem if we put two pieces
    of Plutonium next to each other, the whole chain
    will explode.
  • How many safe chains are there?
  • (Note These are linear chains.)

36
Analysis
  • C(n) Number of Safe Chains of length n.
  • L(n) The number of safe chains of length n that
    END with a piece of lead.
  • P(n) The number of safe chains of length n that
    END with a piece of Plutonium.
  • Example Length 3
  • s LLL s PLL
  • s LLP s PLP
  • s LPL u PPL
  • u LPP u PPP

37
Analysis contd
  • The total number of chains must be the sum of
    those that end with Lead and those that end with
    Plutonium.
  • C(n) L(n) P(n)
  • Now we look at the two terms, assuming that we
    add one new piece to the end.
  • Given are all chains of length n-1. There are
    again C(n-1) of those. To which of them can we
    add a piece of lead? To ALL of them.
  • Therefore, L(n) C(n-1)

38
Analysis Contd
  • Given are all chains of length n-1. There are
    again C(n-1) of those. To which of them can we
    add a piece of Plutonium?
  • Only to those that END with a piece of LEAD!!
    There are L(n-1) of those. Therefore,
  • P(n) L(n-1)
  • C(n) L(n) P(n) C(n-1) L(n-1) C(n-1)
    C(n-2)
  • This is the Fibonacci formula. However, we have
    slightly different base cases here.
  • C(1) 2 P or L
  • C(2) 3 PL of LP or LL
  • Back to our example
  • C(3) C(2) C(1) 3 2 5.
  • Thats exactly what we had before.

39
Mr. Spocks Dilemma
  • There are n planets in an unexplored planetary
    system, but there is fuel for only k visits.
  • How many ways are there for choosing a group of
    planets to visit?
  • Lets think about a specific planet, planet X.
  • Either we visit X, or we dont visit X.
  • C(n, k) number of ways to chose k out of n
  • If we visit X, then we have n-1 choices left, but
    only fuel for k-1 visits.
  • If we dont visit X, then we have n-1 choices
    left, but we still have fuel for k visits.

40
Analysis
  • The total number of ways to choose must be the
    sum of the total number of trips that include the
    planet X and the total number of trips that do
    not include the planet X.
  • C(n, k) C(n-1, k-1) C(n-1, k)
  • This is clearly recursive. Both sub-problems are
    of the same kind and simpler. But are there base
    cases?
  • C(n-1, k-1) eventually C(n-k, 0)
  • C(n-1, k) eventually C(k, k)
  • (n must be greater than k, otherwise we visit all
    planets, and the problem is not a problem.)

41
Last analysis
  • C(k,k) 1 (There is only one way to choose k
    planets out of k planets!)
  • C(n,0) 1 (There is only one way to select no
    planet.)
  • This is a little abstract. We can use C(n, 1) n
    (There are n ways to select 1 planet of n.)

42
The function
  • We are ready for the recursive definition
  • 1 IF k 0
  • C(n,k) 1 IF k n
  • C(n-1, k-1) C(n-1, k) IF 0 lt k lt n
  • 0 IF k gt n
  • int C(int n, int k)
  • if (k gt n)
  • return 0
  • else if (k n)
  • return 1
  • else if (k 0)
  • return 1
  • else
  • return C(n-1, k-1) C(n-1, k)

43
C(4, 2)
C(4,2) Return C(3,1) C(3,2)
C(3,1) Return C(2,0) C(2,1)
C(3,2) Return C(2,1)) C(2,2)
C(2,1) Return C(1,0) C(1,1)
C(2,1) Return C(1,0) C(1,1)
C(2,0) Return 1
C(2,2) Return 1
C(1,0) Return 1
C(1,1) Return 1
C(1,0) Return 1
C(1,1) Return 1
The recursive call that C(4,2) generates
44
A game for guessing number
  • 1. I think of a number between 1 -100.
  • 2. When you guess one, I tell you the number I
    thought is larger or less than the one you
    guessed.
  • 3. Continue step 2 till you guess the right
    number I though of.
  • Write the number of times you guessed.

45
Binary Search
  • How do you find something efficiently in a
  • phone book? Open the phone book in the
  • middle. If what you are looking for is in the
  • first half, then ignore the second half and
  • divide the first half again in the middle. Keep
  • doing this until you find the page. Then
  • divide the page in half, etc.

46
Binary Search
  • More formally Given is A, an array of n numbers
  • We want to verify whether V is in the array.
  • IF n 1 THEN check whether the number is
  • equal to V
  • ELSE BEGIN Find the midpoint of A
  • IF V is greater than the Amidpoint
  • THEN Search recursively in the second half
  • ELSE Search recursively in the first half

47
The function
  • int bins(int A, int V, int fi, int la)
  • if (fi gt la) return -1
  • else
  • int mid (fi la) / 2
  • if (V Amid) return mid
  • else if (V lt Amid)
  • return bins(A,V,fi,mid-1)
  • else
  • return bins(A,V,mid1,la)

48
Discuss
  • Notes We always pass the whole array in.
  • These define the active part of the array
  • - fi ... first
  • - la ... last
  • The return value -1 means that the number was not
    found.
  • Example
  • Array A contains the numbers
  • 0 1 2 3 4 5 6
  • We will look for V 19 first, and V 21 later.
  • cout ltlt bins(A,19,0,6)

1 5 9 13 17 19 23
49
The process of search
  • 1 5 9 13 17 19 23 A 19 V
  • fi m la
  • fi m la
  • Note how we quickly found it!
  • 1 5 9 13 17 19 23 A , 21 V
  • fi m la
  • fi m la
  • fi, m, la
  • la fi
  • Last is now before first and we stop.

50
Attentions!
  • Warning Two common mistakes
  • (1) CORRECT mid (fi1a)/2
  • WRONG mid (Afi Ala)/2
  • (2) CORRECT return bins(A, V, mid1, la)
  • WRONG return bins(A, V, mid, la)

51
Efficiency on large arrays
  • Note Lets say we have an array of 1,000,000
    sorted numbers. (Its better if it has 220
    elements, but thats about 1,000,000.)
  • The first decision eliminates approx. 500,000!
  • The second decision eliminates another 250,000
    numbers.
  • After about 20 runs through the loop, we found
    it. Sequential search might need to go through
    all 1,000,000 elements. (1,000,000 loops)
  • What an improvement!

52
Searching the maximum in an Array
if (A has only one item) MaxArray(A) is the
item in A else if (A has more than one item)
MaxArray(A) is the maximum of MaxArray(left half
of A)
and MaxArray(right half of A)
MaxArray(A)
MaxArray(right half of A)
MaxArray(left half of A)
Recursive solution to the largest-item problem
53
Searching in Array
MaxArray(lt1,6,8,3gt) Return Max(MaxArray(lt1,6gt),
MaxArray(lt8,3gt))
MaxArray(lt1,6gt) Return Max(MaxArray(lt1gt),
MaxArray(lt6gt))
MaxArray(lt8,3gt) Return Max(MaxArray(lt8gt),
MaxArray(lt3gt))
MaxArray(lt1gt) Return 1
MaxArray(lt6gt) Return 6
MaxArray(lt8gt) Return 8
MaxArray(lt3gt) Return 3
The recursive calls that MaxArray(lt1,6,8,3gt)
generates
54
Tower of Hanoi
http//wipos.p.lodz.pl/zylla/games/hanoi3e.html
SolveTowers(Count, Source, Destination, Spare)
if (Count is 1) Move a disk directly from
source to Destination) else
SolveTowers(Count-1, Source, Spare, Destination)
SolveTowers(1, Source, Destination,
Spare) SolveTowers(Count-1, Spare,
Destination, Source)
55
Tower of Hanoi
SolveTowers(3, A, B, C)
SolveTowers(2, A, C, B)
SolveTowers(2, C, B, A)
SolveTowers(1, A, B, C)
SolveTowers(1, A, B, C)
SolveTowers(1, C, A, B)
SolveTowers(1, A, C, B)
SolveTowers(1, C, B, A)
SolveTowers(1, A, B, C)
SolveTowers(1, B, C, A)
The order of recursive calls that results from
SolveTowers(3, A, B, C)
56
Recursion and Efficiency
  • The function call overhead
  • The inefficiency of some recursive algorithm

57
Use iterative (Example)
  • int interativeRabbit(int n)
  • int prev1, curr1, next1
  • for (int i 3 i ltn i)
  • next prevcurr
  • prev curr
  • curr next
  • return next

58
Summary
  • Recursion solves a problem by solving a smaller
    problem of the same type
  • Four questions
  • How can you define the problem in terms of a
    smaller problem of the same type?
  • How does each recursive call diminish the size of
    the problem?
  • What instance(s) of the problem can serve as the
    base case?
  • As the problem size diminishes, will you reach a
    base case?

59
Summary
  • To construct a recursive solution, assume a
    recursive calls postcondition is true if its
    precondition is true
  • The box trace can be used to trace the actions of
    a recursive method
  • Recursion can be used to solve problems whose
    iterative solutions are difficult to conceptualize

60
Summary
  • Some recursive solutions are much less efficient
    than a corresponding iterative solution due to
    their inherently inefficient algorithms and the
    overhead of function calls
  • If you can easily, clearly, and efficiently solve
    a problem by using iteration, you should do so
Write a Comment
User Comments (0)
About PowerShow.com