0% found this document useful (0 votes)
0 views

Lecture 4_ Recursive Algorithms

The document discusses recursive algorithms, defining recursion as a problem-solving approach that breaks problems into smaller subproblems, each defined in terms of itself. Key components include identifying base cases, decomposing problems, and combining results, with examples like calculating factorials and checking for palindromes. It also highlights the efficiency and limitations of recursion compared to iterative methods, emphasizing that while recursion can be simpler to implement, it may involve more overhead and memory usage.

Uploaded by

Walter
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views

Lecture 4_ Recursive Algorithms

The document discusses recursive algorithms, defining recursion as a problem-solving approach that breaks problems into smaller subproblems, each defined in terms of itself. Key components include identifying base cases, decomposing problems, and combining results, with examples like calculating factorials and checking for palindromes. It also highlights the efficiency and limitations of recursion compared to iterative methods, emphasizing that while recursion can be simpler to implement, it may involve more overhead and memory usage.

Uploaded by

Walter
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

Design and Analysis of

Algorithms
Recursive algorithms

Department of Computer Science


Recursive definitions

 A recursive definition is one in which something is


defined in terms of itself
 Almost every algorithm that requires looping can
be defined iteratively or recursively
 All recursive definitions require two parts:
 Base case
 Recursive step
 The recursive step is the one that is defined in
terms of itself
 The recursive step must always move closer to
the base case

2
Recursive algorithm

A recursive algorithm solves the problem by


possibly using the result of applying itself to a
simpler problem

Example: Draw this picture

3
General Recursive Design Strategy

 Identify the base case(s) (for direct solution)

 Devise a problem splitting strategy


 Subproblems must be smaller
 Subproblems must work towards a base case

 Devise a solution combining strategy

4
Requirements for Recursive Solution

 At least one “small” case that you can solve


directly

 A way of breaking a larger problem down into:


 One or more smaller subproblems
 Each of the same kind as the original

 A way of combining subproblem results into an


overall solution to the larger problem

5
Recursive Thinking

Recursion is:
 A problem-solving approach, that can ...
 Generate simple solutions to ...
 Certain kinds of problems that ...
 Would be difficult to solve in other ways

Recursion splits a problem:


 Into one or more simpler versions of itself

6
Recursive Thinking:

The General Approach


1. if problem is “small enough”
2. solve it directly
3. else
4. break into one or more smaller
subproblems
5. solve each subproblem recursively
6. combine results into solution to whole
problem
7
Recursive Thinking

Strategy for searching a sorted array:


1. if the array is empty
2. return -1 as the search result (not present)
3. else if the middle element == target
4. return subscript of the middle element
5. else if target < middle element
6. recursively search elements before middle
7. else
8. recursively search elements after the middle

8
Recursive Design Example

Recursive algorithm for finding length of a string:


1. if string is empty (no characters)
2. return 0  base case
3. else  recursive case
4. compute length of string without first character
5. return 1 + that length

Note: Not best technique for this problem; illustrates the


approach.

9
Recursive algorithm Properties
A recursive algorithm solves the large problem
by using its solution to a simpler sub-problem
 divide and conquer approach

Eventually the sub-problem is simple enough


that it can be solved without applying the
algorithm to it recursively
 This is called the ‘base case’

10
Key Components of a Recursive Algorithm
Design
1. What is a smaller identical problem(s)?
 Decomposition

2. How are the answers to smaller problems


combined to form the answer to the larger
problem?
 Composition

3. Which is the smallest problem that can be solved


easily (without further decomposition)?
 Base/stopping case

11
Recursion

A recursive procedure can often be analyzed


by solving a recursive equation
Basic form:
T(n) = if (base case) then some constant
else ( time to solve subproblems +
time to combine solutions )
Result depends upon
 how many subproblems
 how much smaller are subproblems
 how costly it is to combine solutions (coefficients)
12
Example: Factorial Function

The factorial function: multiply together all


numbers from 1 to n.
denoted n!
n!=n*(n-1)*(n-2)*…2*1

n!= n*(n-1)! if n>0 General case: Uses a solution to


a simpler sub-problem
1 if n==0 Base case: Solution is given
directly

13
public static int factorial(int n)
Execution Trace {
int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
(decomposition) else // base case
fact = 1;
return fact;
}

factorial(4)

factorial(3) 4

14
public static int factorial(int n)
{
Execution Trace int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
else // base case
(decomposition) fact = 1;
return fact;
}

factorial(4)

factorial(3) 4

factorial(2) 3

15
public static int factorial(int n)
Execution Trace {
int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
(decomposition) else // base case
fact = 1;
return fact;
}

factorial(4)

factorial(3) 4

factorial(2) 3

factorial(1) 2

16
public static int factorial(int n)
Execution Trace {
int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
(composition) else // base case
fact = 1;
return fact;
}

factorial(4)

*
factorial(3) 4

*
factorial(2) 3

*
factorial(1) ->1 2

17
public static int factorial(int n)
{
Execution Trace int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
else // base case
(composition) fact = 1;
return fact;
}

factorial(4)
*
factorial(3) 4

*
factorial(2) ->2 3

18
public static int factorial(int n)
Execution Trace {
int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
(composition) else // base case
fact = 1;
return fact;
}

factorial(4)
*
factorial(3) ->6 4

19
public static int factorial(int n)
Execution Trace {
int fact;
if (n > 1) // recursive case (decomposition)
fact = factorial(n – 1) * n; (composition)
(composition) else // base case
fact = 1;
return fact;
}

factorial(4) -> 24

20
Improved factorial Method

public static int factorial(int n)


{
int fact=1; // base case value

if (n > 1) // recursive case (decomposition)


fact = factorial(n – 1) * n; // composition
// else do nothing; base case

return fact;
}

21
Example: Palindrome

Describe a palindrome recursively ( a palindrome


is a word that has the same spelling both forward
and backwards e.g. bob)

Base case:
 An empty string is a palindrome
 A string of one character is a palindrome
Recursive step
 If S is a palindrome, then aSb is also a palindrome if
a=b

22
How Recursion Works

To truly understand how recursion works we need


to first explore how any function call works.
When a program calls a subroutine (function) the
current function must suspend its processing.
The called function then takes over control of the
program.
When the function is finished, it needs to return to
the function that called it.
The calling function then ‘wakes up’ and continues
processing.

23
How Recursion Works
One important point in this interaction is that,
unless changed through call-by- reference, all local
data in the calling module must remain unchanged.
Therefore, when a function is called, some
information needs to be saved in order to return
the calling module back to its original state (i.e., the
state it was in before the call).
We need to save information such as the local
variables and the spot in the code to return to after
the called function is finished.

24
How Recursion Works
To do this we use a stack.
Before a function is called, all relevant data is
stored in a stackframe.
This stackframe is then pushed onto the system
stack.
After the called function is finished, it simply pops
the system stack to return to the original state.
By using a stack, we can have functions call other
functions which can call other functions, etc.
Because the stack is a first-in, last-out data
structure, as the stackframes are popped, the data
comes out in the correct order.
25
Limitations of Recursion

Recursive solutions may involve extensive


overhead because they use calls.
When a call is made, it takes time to build a
stackframe and push it onto the system stack.
Conversely, when a return is executed, the
stackframe must be popped from the stack and the
local variables reset to their previous values – this
also takes time.
Every time we make a call, we must use some of
the memory resources to make room for the
stackframe.
26
Recurrences

The expression:
 c n 1

T ( n)  

2T    c n  1
n
  2 
is a recurrence.
 Recurrence: an equation that describes a
function in terms of its value on smaller functions

27
Recurrence Examples

 0 n0  0 n0
s ( n)   s ( n)  
c  s(n  1) n  0 n  s(n  1) n  0

n 1 
 c  c n 1
 
T ( n)   T ( n)  
2T  n   c n  1  n
  2  aT    cn n  1
 b
28
Solving Recurrences

Recurrences can be solved by the following


methods
 Substitution method

 Iteration method

 Master method

 Recursive tree method

29
The substitution method

A.k.a. the “making a good guess method”


Guess the form of the answer, then use induction
to find the constants and show that solution works

Examples:
 T(n) = 2T(n/2) + (n)  T(n) = (n lg n)

 T(n) = 2T(n/2) + n  T(n) = (n lg n)

 T(n) = 2T(n/2+ 17) + n  (n lg n)

30
The Iteration method

Another option for solving recurrences the


“iteration method”
 Expand the recurrence

 Work some algebra to express as a summation

 Evaluate the summation

31
The Iteration method

 T(n) =  c n 1
 n
2T(n/2) + c T (n)  2T
   c n 1
2(2T(n/2/2) + c) + c   2 
22T(n/22) + 2c + c
22(2T(n/22/2) + c) + 3c
23T(n/23) + 4c + 3c
23T(n/23) + 7c
23(2T(n/23/2) + c) + 7c
24T(n/24) + 15c

2kT(n/2k) + (2k - 1)c

32
The Iteration method

So far for n > 2k we have


 T(n) = 2kT(n/2k) + (2k - 1)c
What if k = lg n?
 T(n) = 2lg n T(n/2lg n) + (2lg n - 1)c Note: 2lg n=n
= n T(n/n) + (n - 1)c
= n T(1) + (n-1)c
= nc + (n-1)c = (2n - 1)c
 c n 1
 n
T (n)  2T
   c n 1
  2 
33
Proving a Recursive Method
Correct
Recall Proof by Induction:
1. Prove the theorem for the base case(s): n=0
2. Show that:
 If the theorem is assumed true for n,
 Then it must be true for n+1

Result: Theorem true for all n ≥ 0.

34
Proving a Recursive Method Correct

Recursive proof is similar to induction:


1. Show base case recognized and solved
correctly
2. Show that
 If all smaller problems are solved correctly,
 Then original problem is also solved
correctly
3. Show that each recursive case makes
progress towards the base case 
terminates properly

35
Recursive Versus Iterative
Methods

All recursive algorithms/methods


can be rewritten without recursion.

Iterative methods use loops instead of recursion

Iterative methods generally run faster and use


less memory--less overhead in keeping track of
method calls

36
Recursion Versus Iteration

Recursion and iteration are similar


Iteration:
 Loop repetition test determines whether to exit
Recursion:
 Condition tests for a base case
Can always write iterative solution to a
problem solved recursively, but:
Recursive code often simpler than iterative
 Thus easier to write, read, and debug
37
Efficiency of Recursion

Recursive method often slower than iterative;


why?
 Overhead for loop repetition smaller than
 Overhead for call and return
If easier to develop algorithm using recursion,
 Then code it as a recursive method:
 Software engineering benefit probably outweighs
...
 Reduction in efficiency
Don’t “optimize” prematurely!
38
So When Should You Use Recursion?

Solutions/algorithms for some problems are


inherently recursive
 iterative implementation could be more
complicated
When efficiency is less important
 it might make the code easier to understand

Bottom line is about:


 Algorithm design

 Tradeoff between readability and efficiency

39
Towers of Hanoi: Description

Goal: Move entire tower to another peg


Rules:
1. You can move only the top disk from a peg.
2. You can only put a smaller on a larger disk
(or on an empty peg)

40
Towers of Hanoi: Solution Strategy

41
Towers of Hanoi: Solution Strategy

42
Towers of Hanoi: Recursion Structure

move(n, src, dst, tmp) =


if n == 1: move disk 1 from src to dst
otherwise:
move(n-1, src, tmp, dst)
move disk n from src to dst
move(n-1, tmp, dst, src)

43
Computing Powers

The power function, p(x,n)=xn, can be defined


recursively:
 1 if n  0
p ( x, n )  
 x  p( x, n  1) else
This leads to a power function that runs in O(n)
time (for we make n recursive calls).
We can do better than this, however.

44
Recursive Squaring

We can derive a more efficient linearly recursive


algorithm by using repeated squaring:

 1 if x  0

p( x, n)   x  p( x, (n  1) / 2) if x  0 is odd
2

 p( x, n / 2) 2 if x  0 is even

For example,
24 = 2(4/2)2 = (24/2)2 = (22)2 = 42 = 16
25 = 21+(4/2)2 = 2(24/2)2 = 2(22)2 = 2(42) = 32
26 = 2(6/ 2)2 = (26/2)2 = (23)2 = 82 = 64
27 = 21+(6/2)2 = 2(26/2)2 = 2(23)2 = 2(82) = 128. 45
A Recursive Squaring Method

Algorithm Power(x, n):


Input: A number x and integer n = 0
Output: The value xn
if n = 0 then
return 1
if n is odd then
y = Power(x, (n - 1)/ 2)
return x · y ·y
else
y = Power(x, n/ 2)
return y · y

46
Analyzing the Recursive Squaring
Method

Algorithm Power(x, n):


Input: A number x and
integer n = 0
Output: The value xn Each time we make a
recursive call we halve the
if n = 0 then
value of n; hence, we make
return 1 log n recursive calls. That
if n is odd then is, this method runs in
y = Power(x, (n - 1)/ 2) O(log n) time.
return x · y · y
else It is important that we
used a variable twice
y = Power(x, n/ 2)
here rather than calling
return y · y the method twice.

47
Conclusion

A recursive solution solves a problem by solving a


smaller instance of the same problem.
It solves this new problem by solving an even
smaller instance of the same problem.
Eventually, the new problem will be so small that
its solution will be either obvious or known.
This solution will lead to the solution of the original
problem.

48

You might also like