Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
2 views

Lecture05_Recursion

The document discusses recursion in programming, particularly focusing on its definition, patterns, and examples such as the factorial function and drawing ticks on an English ruler. It explains key concepts like base cases, recursive calls, linear and binary recursion, and provides algorithms for tasks like summing an array and computing Fibonacci numbers. Additionally, it highlights the efficiency of recursive methods and introduces concepts like tail recursion and recursive squaring.

Uploaded by

Đức An Phạm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Lecture05_Recursion

The document discusses recursion in programming, particularly focusing on its definition, patterns, and examples such as the factorial function and drawing ticks on an English ruler. It explains key concepts like base cases, recursive calls, linear and binary recursion, and provides algorithms for tasks like summing an array and computing Fibonacci numbers. Additionally, it highlights the efficiency of recursive methods and introduces concepts like tail recursion and recursive squaring.

Uploaded by

Đức An Phạm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

Data Structures and

Algorithms
"
Recursion!
The Recursion Pattern"
• Recursion: when a method calls itself!
• Classic example--the factorial function:!
– n! = 1· 2· 3· ··· · (n-1)· n!
• Recursive definition:!

⎧ 1 if n = 0
f (n) = ⎨
⎩n ⋅ f (n − 1) else

Phạm Bảo Sơn - DSA


The Recursion Pattern"

• As a Java method:!
// recursive factorial function
public static int recursiveFactorial(int n) {
if (n == 0) return 1;
// base case
else return n * recursiveFactorial(n- 1); //
recursive case
}!

Phạm Bảo Sơn - DSA


Content of a Recursive
Method"
• Base case(s). !
– Values of the input variables for which we perform
no recursive calls are called base cases (there
should be at least one base case). !
– Every possible chain of recursive calls must
eventually reach a base case.!
• Recursive calls. !
– Calls to the current method. !
– Each recursive call should be defined so that it
makes progress towards a base case.!
Phạm Bảo Sơn - DSA
Visualizing Recursion"
Example recursion trace:
• Recursion trace!
return 4*6 = 24 final answer
• A box for each call

recursiveFactorial(4)
recursive call! call return 3*2 = 6

• An arrow from each recursiveFactorial(3)


call return 2*1 = 2
caller to callee! recursiveFactorial(2)

• An arrow from each call return 1*1 = 1


recursiveFactorial(1)
callee to caller call return 1
showing return value! recursiveFactorial(0)

Phạm Bảo Sơn - DSA


Example – English Rulers"
• Define a recursive way to print the ticks and
numbers like an English ruler:!

Phạm Bảo Sơn - DSA


A Recursive Method for
Drawing Ticks on an English
Ruler"
// draw a tick with no label
public static void drawOneTick(int tickLength) { drawOneTick(tickLength, - 1); }
// draw one tick
public static void drawOneTick(int tickLength, int tickLabel) {
for (int i = 0; i < tickLength; i++)

System.out.print("-");

if (tickLabel >= 0) System.out.print(" " + tickLabel);

System.out.print("\n");

}
public static void drawTicks(int tickLength) { // draw ticks of given length
if (tickLength > 0) { // stop when length drops to 0
drawTicks(tickLength- 1);
// recursively draw left ticks
drawOneTick(tickLength);
// draw center tick
drawTicks(tickLength- 1);
// recursively draw right ticks
}
}
public static void drawRuler(int nInches, int majorLength) { // draw ruler
drawOneTick(majorLength, 0);
// draw tick 0 and its label
for (int i = 1; i <= nInches; i++)
{
drawTicks(majorLength- 1);
// draw ticks for this inch
drawOneTick(majorLength, i);
// draw tick i and its label
}
}
!
!
! Phạm Bảo Sơn - DSA
Visualizing the DrawTicks
Method"
• An interval with a drawTicks (3 ) Output

drawTicks (2 )
central tick length L >1 drawTicks (1 )
is composed of the drawTicks ( 0 )

following:! drawOneTick (1 )

– an interval with a central drawTicks ( 0 )

drawOneTick (2 )
tick length L-1,!
drawTicks (1 )
– a single tick of length L,!
drawTicks (0 )
– an interval with a central drawOneTick (1 )
tick length L-1.! drawTicks (0 )
drawOneTick (3 )

drawTicks (2 )
(previous pattern repeats )

Phạm Bảo Sơn - DSA


Recall the Recursion Pattern"
• Recursion: when a method calls itself!
• Classic example--the factorial function:!
– n! = 1· 2· 3· ··· · (n-1)· n!
• Recursive definition:!

⎧ 1 if n = 0
f (n) = ⎨
⎩n ⋅ f (n − 1) else
• As a Java method:!
// recursive factorial function
public static int recursiveFactorial(int n) {
if (n == 0) return 1;
// base case
else return n * recursiveFactorial(n- 1);
// recursive case
}!
Phạm Bảo Sơn - DSA
Linear Recursion"
• Test for base cases. !
– Begin by testing for a set of base cases (there should be at
least one). !
– Every possible chain of recursive calls must eventually reach
a base case, and the handling of each base case should not
use recursion.!
• Recur once. !
– Perform a single recursive call. (This recursive step may
involve a test that decides which of several possible recursive
calls to make, but it should ultimately choose to make just
one of these calls each time we perform this step.)!
– Define each possible recursive call so that it makes progress
towards a base case.!

Phạm Bảo Sơn - DSA


A Simple Example of Linear
Recursion"
Algorithm LinearSum(A, n):! Example recursion trace:
Input: !
An integer array A and an call return 15 + A[4] = 15 + 5 = 20
integer n >= 1, such that A has LinearSum (A,5)
at least n elements! call return 13 + A[3] = 13 + 2 = 15
Output: ! LinearSum (A,4)
The sum of the first n integers in call return 7 + A [2 ] = 7 + 6 = 13
A! LinearSum (A,3)
if n = 1 then" call return 4 + A [1 ] = 4 + 3 = 7
return A[0]! LinearSum (A,2)
else" call return A[0] = 4

return LinearSum(A, n - 1) + A[n LinearSum (A,1)


- 1]!
!

Phạm Bảo Sơn - DSA


Reversing an Array"
Algorithm ReverseArray(A, i, j):!
Input: An array A and nonnegative integer
indices i and j!
Output: The reversal of the elements in A
starting at index i and ending at j!
if i < j then"
! !Swap A[i] and A[ j]!
! !ReverseArray(A, i + 1, j - 1)!
return!
Phạm Bảo Sơn - DSA
Defining Arguments for
Recursion"
• In creating recursive methods, it is important
to define the methods in ways that facilitate
recursion.!
• This sometimes requires we define additional
paramaters that are passed to the method.!
• For example, we defined the array reversal
method as ReverseArray(A, i, j), not
ReverseArray(A).!

Phạm Bảo Sơn - DSA


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.!
!

Phạm Bảo Sơn - DSA


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) 2 if x > 0 is odd
⎪ 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.!

Phạm Bảo Sơn - DSA


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!
Phạm Bảo Sơn - DSA
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
if n = 0 !then" recursive call we halve the
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 here
! !y = Power(x, n/ 2)! rather than calling the
" "return y · y! method twice.
Phạm Bảo Sơn - DSA

Tail Recursion "
Tail recursion occurs when a linearly recursive method makes
its recursive call as its last step.!
• The array reversal method is an example.!
• Such methods can be easily converted to non-recursive
methods (which saves on some resources).!
• Example:!
Algorithm IterativeReverseArray(A, i, j ):!
Input: An array A and nonnegative integer indices i and j!
Output: The reversal of the elements in A starting at index i and
ending at j!
while i < j do"
!Swap A[i ] and A[ j ]!
!i = i + 1!
!j = j - 1!
return!

Phạm Bảo Sơn - DSA


Binary Recursion"
• Binary recursion occurs whenever there are
two recursive calls for each non-base case.!
• Example: the DrawTicks method for drawing
ticks on an English ruler.!

Phạm Bảo Sơn - DSA


A Binary Recursive Method for
Drawing Ticks"
// draw a tick with no label
public static void drawOneTick(int tickLength) { drawOneTick(tickLength, - 1); }
// draw one tick
public static void drawOneTick(int tickLength, int tickLabel) {
for (int i = 0; i < tickLength; i++)

System.out.print("-");

if (tickLabel >= 0) System.out.print(" " + tickLabel);

Note the two


System.out.print("\n");

}
public static void drawTicks(int tickLength) { // draw ticks of given length
if (tickLength > 0) { // stop when length drops to 0
recursive calls
drawTicks(tickLength- 1);
// recursively draw left ticks
drawOneTick(tickLength);
// draw center tick
drawTicks(tickLength- 1);
// recursively draw right ticks
}
}
public static void drawRuler(int nInches, int majorLength) { // draw ruler
drawOneTick(majorLength, 0);
// draw tick 0 and its label
for (int i = 1; i <= nInches; i++)
{
drawTicks(majorLength- 1);
// draw ticks for this inch
drawOneTick(majorLength, i);
// draw tick i and its label
}
}
!
!
! Phạm Bảo Sơn - DSA
Another Binary Recusive
Method"
• Problem: add all the numbers in an integer array A:!
Algorithm BinarySum(A, i, n):!
Input: An array A and integers i and n!
Output: The sum of the n integers in A starting at index i!
if n = 1 then"
" return A[i ]!
return BinarySum(A, i, n/ 2) + BinarySum(A, i + n/ 2, n/ 2)!

• Example trace:"
0, 8

0, 4 4, 4
0, 2 2, 2 4, 2 6, 2

0, 1 1, 1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1

Phạm Bảo Sơn - DSA


Computing Fibonacci
Numbers"
• Fibonacci numbers are defined recursively:!
F0 = 0

F1 = 1

Fi = Fi-1 + Fi-2 for i > 1.

• As a recursive algorithm (first attempt):!
Algorithm BinaryFib(k):

Input: Nonnegative integer k

Output: The kth Fibonacci number Fk

if k <= 1 then



return k

else



return BinaryFib(k - 1) + BinaryFib(k - 2)!
Phạm Bảo Sơn - DSA
Analyzing the Binary
Recursion Fibonacci Algorithm"
• Let nk denote number of recursive calls made by
BinaryFib(k). Then!
– n0 = 1 !!
– n1 = 1 !!
– n2 = n1 + n0 + 1 = 1 + 1 + 1 = 3 !!
– n3 = n2 + n1 + 1 = 3 + 1 + 1 = 5 !!
– n4 = n3 + n2 + 1 = 5 + 3 + 1 = 9 !!
– n5 = n4 + n3 + 1 = 9 + 5 + 1 = 15 !!
– n6 = n5 + n4 + 1 = 15 + 9 + 1 = 25 !!
– n7 = n6 + n5 + 1 = 25 + 15 + 1 = 41 !!
– n8 = n7 + n6 + 1 = 41 + 25 + 1 = 67.!
• Note that the value at least doubles for every other
value of nk. It is exponential!!

Phạm Bảo Sơn - DSA


A Better Fibonacci
Algorithm"
• Use linear recursion instead:!
Algorithm LinearFibonacci(k):!
Input: A nonnegative integer k!
Output: Pair of Fibonacci numbers (Fk, Fk-1)!
if k = 1 then"
" "return (k, 0)!
else"
! !(i, j) = LinearFibonacci(k - 1)!
" "return (i +j, i)!

• Runs in O(k) time.!


Phạm Bảo Sơn - DSA
Multiple Recursion"
• Motivating example: summation puzzles!
• pot + pan = bib !!
• dog + cat = pig !!
• boy + girl = baby !!

• Multiple recursion: makes potentially many


recursive calls (not just one or two).!
• Find all subset of a certain length.!

Phạm Bảo Sơn - DSA

!
Algorithm for Multiple
Recursion"
Algorithm PuzzleSolve(k,S,U):!
Input: An integer k, sequence S, and set U (the universe of elements to test)!
Output: An enumeration of all k-length extensions to S using elements in U!
!without repetitions!
if k = 0 then"
!Test whether S is a configuration that solves the puzzle!
"if S solves the puzzle then"
" "return “Solution found: ” S!
else !
for all e in U do"
! !Remove e from U !{e is now being used}!
! !Add e to the end of S!
" "PuzzleSolve(k - 1, S,U)!
! !Add e back to U !{e is now unused}!
! !Remove e from the end of S!
!

Phạm Bảo Sơn - DSA


Visualizing PuzzleSolve"

Initial call

PuzzleSolve( 3,(),{a,b,c})

PuzzleSolve(2,a,{b, c}) PuzzleSolve(2,b,{a, c}) PuzzleSolve(2,c,{a,b} )

PuzzleSolve(1,ab,{c} ) PuzzleSolve(1,ba,{c}) PuzzleSolve(1,ca,{b} )


abc bac cab
PuzzleSolve(1,ac,{b} ) PuzzleSolve(1,bc,{a} ) PuzzleSolve(1,cb,{a})
acb bca cba

Phạm Bảo Sơn - DSA

You might also like