Recursion
1
Function calls
What happens when a function calls another functions ?
When a function terminates, its call A new function call opens a new
frame is removed from the stack frame to store local variables
h() s “h “
g() s “g “
f start
g start
f() s “f “
h start
h done
g done
Call Stack
f done
(LIFO) 2
Calculating Factorial
• n! = 1*2*3*…(n-1)*n
• An iterative implementation:
• An alternative Recursive definition:
• n! = n * (n-1)!
• 0! = 1
• Can we use this approach to implement another version of
factorial calculation in Python ?
3
Iterative Versus Recursive
Step by step (iteratively):
n! = 1*2*3*….*n 4! = 1*2*3*4 = 2*3*4 = 6*4 = 24
n iterations
Recursively:
n! = n*(n-1)! 4! = 4*3!
0! = 1 = 4*(3*2!)
= 4*(3*(2*1!))
=4*(3*(2*(1*0!)))
=4*(3*(2*(1*1)))
=4*(3*(2*1))
= 4*(3*2) = 4*6 = 24
4
Recursive Definition
Factorial
Calculate result using a recursive call
n! = n * (n-1)!
0! = 1
Smaller instance
Base condition
5
Recursive Implementation of
Factorial in Python
def factorial(n): stop condition
if n == 0:
return 1
return n * factorial(n-1)
calculate the result advance towards base case
using a recursive call
6
Recursion
Recursive function:
A function whose implementation calls itself (with different
arguments).
Recursive Solution
A solution to a “large” problem using solutions to “small”
problems that assemble it.
7
Recursive factorial – step by step
factorial(
4)n
4
Returns…
8
Recursive factorial – step by step
factorial(
4)n
4
Returns…
9
Recursive factorial – step by step
factorial(
4)n
4
Returns…
4*…
10
Recursive factorial – step by step
factorial(
factorial(
4)n
3)n
4
3
Returns…
Returns…
4*…
11
Recursive factorial – step by step
factorial(
factorial(
4)n
3)n
4
3
Returns…
Returns…
4*…
12
Recursive factorial – step by step
factorial(
factorial(
4)n
3)n
4
3
Returns…
Returns…
4*…
3*…
13
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n
2)n
4
3
2
Returns…
Returns…
4*… Returns…
3*…
14
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n
2)n
4
3
2
Returns…
Returns…
4*… Returns…
3*…
15
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n
2)n
4
3
2
Returns…
Returns…
4*… Returns…
3*…
2*…
16
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n
4 1)n
3
2
Returns… 1
Returns…
4*… Returns…
3*… Returns…
2*…
17
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n
4 1)n
3
2
Returns… 1
Returns…
4*… Returns…
3*… Returns…
2*…
18
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n
4 1)n
3
2
Returns… 1
Returns…
4*… Returns…
3*… Returns…
2*…
1*…
19
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n
4 1)n
3
2
Returns… 1
Returns…
4*… Returns…
3*… Returns…
2*…
1*…
20
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n factorial(
4 1)n
3 0)n
2
Returns… 1
Returns… 0
4*… Returns…
3*… Returns…
2*… Returns…
1*…
21
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n factorial(
4 1)n
3 0)n
2
Returns… 1
Returns… 0
4*… Returns…
3*… Returns…
2*… Returns…
1*…
1
22
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n factorial(
2)n
4 1)n
3
2
Returns… 1
Returns…
4*… Returns…
3*… Returns…
2*…
1*1
23
Recursive factorial – step by step
factorial(
factorial(
4)n factorial(
3)n
2)n
4
3
2
Returns…
Returns…
4*… Returns…
3*…
2*1
24
Recursive factorial – step by step
factorial(
factorial(
4)n
3)n
4
3
Returns…
Returns…
4*…
3*2
25
Recursive factorial – step by step
factorial(
4)n
4
Returns…
4*6
26
Recursion
In every recursive call the problem is reduced.
When the problem is small enough - solve
directly (base case).
A divide and conquer
strategy
27
General Form of Recursive Algorithms
Recursive case - decomposable problem.
Must be:
- at least one base case (the stop condition)
- at least one recursive call.
28
Short Summary
Design a recursive algorithm by
1. Breaking of big problems to smaller problems
2. Solving base cases directly.
Recursive algorithms have
1. Stopping criteria
2. Recursive call(s)
3. A solution that uses solutions of smaller cases
29
Example: Fibonacci Series
• Fibonacci series
0, 1, 1, 2, 3, 5, 8, 13, 21, 34
• Definition:
• fib(0) = 0
• fib(1) = 1
• fib(n) = fib(n-1) + fib(n-2)
30
Fibonacci
“Naturally” recursive
Therefore, the recursive definition is:
• fib(0) = 0 Base case
• fib(1) = 1 Base case
• fib(n) = fib(n-1) + fib(n-2) +
Recursive call
31
Example: Modulo
Given the following iterative version of modulo
calculation - find the recursive definition
1. Base case?
2. What is the recursive call?
3. How do we use the result of the recursive call to
calculate the value for n?
32
Solution: Recursive Modulo
33
Recursive List sum
• Given a list of numbers, calculate their sum using a recursive
function.
13
13
• Now write an alternative implantation that does not use slicing..
34
Recursive List sum
13
13
13
35
Additional examples
• Calculating the sum of sub-lists
• Using slicing
• Using indices (more efficient)
• Odd-Even
36
Recursive Sub-lists Sum
• Input: a list of lists, each internal list contains only
numbers
• Output: a list that contains the sums of each internal
list from the input.
• For example:
• For [ [1,2,3], [4] ] the result is [6, 4]
37
Recursive Sub-lists Sum
• More examples:
In this call, the input contains only one list.
The list has no elements, so its sum is 0.
In this call, there are no lists to sum, so
the output would be en empty list
The number of elements in the
returned list equals to the
number of lists in the input list
38
Recursive Sub-lists Sum
• The recursive implementation has 3 steps:
• Stop condition
• Advance toward the base case
• Solve the problem using a recursive call
Recursive Sub-lists Sum– base case
Easy!
Advancing towards the base condition
• The input is a list
• The base condition is an empty list
• A recursive call with a shorter list is considered to
be an easier case.
• Usually take off the first or last element
• In addition, we advance toward the base list: if we
take elements off the list, eventually we’ll get an
empty list.
Using the recursive call
Having an actual example may help
let’s consider this example [[1,2,3], [5],[6,1]]
input result
Our problem [[1,2,3], [5],[6,1]] [6, 5, 7]
Recursive call [[1,2,3], [5]] [6, 5]
How can we use the result of the recursive call?
If we got [6, 5], we need to append 7 to the list.
How do we get the item 7?
It’s the sum of the list [6,1]
Using the recursive call
input result
Our problem [[1,2,3], [5],[6,1]] [6, 5, 7]
Recursive call [[1,2,3], [5]] [6, 5]
• Our plan:
• Given a list:
• Put aside the last element
• Recursive call with a shorter list and save the
result
• Add to this result the sum of the last element we
put aside.
• Return the result.
And now in Python
recursive_res contains the result
of the recursive call
sum up the elements of the list
we put aside
Shorted version
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = []
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = []
recursive_res = ?
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = []
recursive_res = ?
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = []
recursive_res = ?
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = []
recursive_res = ? recursive_res = ?
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]] lst = []
[]
res = [] res = [] Stop condition!
recursive_res = ? recursive_res = ?
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = []
recursive_res = ? recursive_res = []
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = []
recursive_res = ? recursive_res = []
last_sum = 6
sum([1,2,3])
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = [] Copy all elements from
recursive_res to res
recursive_res = ? recursive_res = []
last_sum = 6
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] res = [6]
recursive_res = ? recursive_res = []
last_sum = 6
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]] lst = [[1,2,3]]
res = [] [6] res = [6]
recursive_res = ? recursive_res = []
last_sum = 6
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = []
recursive_res = [6]
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = []
recursive_res = [6]
last_sum = 9
sum([4,5])
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = [6] Copy all elements from
recursive_res to res
recursive_res = [6]
last_sum = 9
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = [6, 9]
recursive_res = [6]
last_sum = 9
Execution example for [[1,2,3], [4,5]]
lst = [[1,2,3], [4,5]]
res = [6, 9] As expected, the returned value
recursive_res = [6] is [6,9]
last_sum = 9
Alternative solution for recursively calculating the sum of
sub-lists:
WORKING WITH INDICES INSTEAD
OF SLICING STRINGS
62
Is the solution for Recursive Sum the
?most efficient
• In each recursive step we use slicing, which creates a
new (shorter) list
• Can we avoid slicing?
Recursive Sum – alternative solution
• We can use the same list for all the recursive calls.
• But how do we generate an “easier” problem?
• Add another parameter – the index of the current item
Recursive Sum – alternative solution
• Our plan:
• Given a list(lst) + the index of the current item (i):
• Put aside the last element lst[i]
• Recursive call with the shorter list the same list
and the index i-1 and save the result
• Add to this result the sum of the last element we
put aside.
• Return the result.
Recursive Sum – alternative solution
• The stop condition:
• Previously: stop when len(lst) == 0
• Now:
• What about i==0?
Not good! When i == 0 we still have one element to
consider: lst[i]
• The corrent condition is: i == -1:
This indicate that we went over all the elements in the list
Recursive Sum – alternative solution
Recursive Sum – alternative solution
Are we done?
• We Changed our implementation, but the users of
rec_sum still use the previous version with a single
parameter.
• Do the users need to know about the new parameter? It’s
a matter of our implementation.
Recursive Sum – alternative solution
• Our solution: a helper function
The users don’t know this function,
they only know rec_sum
When we call rec_sum_helper
we need to send the index of
.the last item in the list
If the list has 3 elements, the
index of the last item is 2,
therefore we use
len(lst) - 1
Example: Odd-Even
• Given a function odd(n)
• Odd n - return True, Even n – return False
• Write a function even(n) that:
• Even n - return True, Odd n – return False
• This is easy!
70
Odd-Even
71
Odd-Even
Is this implementation correct?
72
Odd-Even
73
Odd-Even
We never return False!
74