Chapter_6_Recursion
Chapter_6_Recursion
Recursion
2024-2025
COMP1117A Computer Programming
Dr. T.W. Chim ([email protected]) & Dr. H.F. Ting ([email protected])
Department of Computer Science, The University of Hong Kong
We are going to learn…
Recursion and memorization
Understand the recursive strategy to tackle the following problems
Factorial
Palindrome
Greatest Common Divisor
Fibonacci number
MergeSort
Tower of Hanoi
2
Section 6.1
Recursion
Recursion
A function definition may contain a call to the function being defined.
In such cases, the function is said to be recursive.
print(factorialIterative(6))
5
Iterative vs. recursive
For recursive approach, we need the following: Option 2 :
Base case – the smallest problem with solution available. Another option is
E.g., 0! = 1. to use a recursive
Divide and conquer – breaking a larger problem into approach to
smaller problem(s). compute n!
E.g., n! = n * (n - 1)!
Larger problem Smaller problem
6
Iterative vs. recursive
def f(n):
if n == 0: Base case
return 1
If n is 0, that means finding 0!,
else:
which is simply 1.
return n * f(n-1)
print(f(6))
7
Iterative vs. recursive
def f(n):
if n == 0: Progress
return 1
If n is not 0, we need to obtain the
else:
result of (n-1)!, with that result,
return n * f(n-1)
we simply need to multiply that by
n to obtain n!
print(f(6))
n 6 n 5
10
Iterative vs. recursive
def f(n): Eventually, f(0) will be
if n == 0:
called. In that case, n equals
return 1
else: 0, and we will have no
return n * f(n-1) further recursive calls.
The value 1 is returned in
print(f(6)) f(0).
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
11
Iterative vs. recursive
def f(n): With f(0) return, the
if n == 0:
execution goes back to f(1)
return 1
else: and continue the suspended
return n * f(n-1) part with f(0) = 1 to the
return statement of f(1).
print(f(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
return 1 * 1
return 1 12
Iterative vs. recursive
def f(n): So this is why we need to have
if n == 0:
return n * f(n-1)
return 1
else: But not just
return n * f(n-1) n * f(n-1)
print(f(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
return 2 * 1 return 1 * 1
return 2 return 1 13
Iterative vs. recursive
def f(n): So this is why we need to have
if n == 0:
return n * f(n-1)
return 1
else: But not just
return n * f(n-1) n * f(n-1)
print(f(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
print(f(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
print(f(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
print(f(6)) print(factorialIterative(6))
f(6) f(5) f (4) f(3) f(2) f(1) f(0)
n 6 n 5 n 4 n 3 n 2 n 1 n 0
return 6 * f(6-1) return 5 * f(5-1) return 4 * f(4-1) return 3 * f(3-1) return 2 * f(2-1) return 1 * f(1-1) return 1
return 6 * f(5) return 5 * f(4) return 4 * f(3) return 3 * f(2) return 2 * f(1) return 1 * f(0)
18
Example 1 Recursive palindrome
-ve index -ve index
-6 -5 -4 -3 -2 -1 -6 -5 -4 -3 -2 -1
+ve index 0 1 2 3 4 5 0 1 2 3 4 5 +ve index
b a c c a b b a c k a b
Iterative:
def isPalindrome(s):
If the first slot is NOT equal for i in range(0, len(s)//2):
to the last slot, it is not a if s[i] != s[-(i+1)]:
palindrome. return False
Then, if the 2nd slot is NOT return True
Iterative approach
equal to the 2nd last slot, it is
not palindrome, …etc Note: String negative index counts from the
last character (-1, -2, …) 19
Example 1 Recursive palindrome
0 1 2 3 4 5
b a c c a b
len(s)=6 Larger problem
0 1 2 3
a c c a
len(s)=4 Smaller problem
0 1 2 3 0 1 2 3 4
a c c a a c d c a
0 1 0 1 2
c c c d c
0
Empty string Base cases d
Question 2. What
is/are the base case(s) When s is empty
that the solution is string or len(s)==1,
readily available? s is a palindrome.
21
Example 1 Recursive palindrome
0 1 2 3 4 5 6
b a c d c a b
22
Example 1 Recursive palindrome
Ok, the first and the last slots are the same. 0 1 2 3 4 5 6
I want to ask if acdca is a palindrome? b a c d c a b
Ok, the first and the last slots are the same. 0 1 2 3 4
I want to ask if cdc is a palindrome? Progress a c d c a
towards
the base
Ok, the first and the last slots are the same.
I want to ask if d is a palindrome?
case 0 1 2
c d c
Yes! d is a 0
palindrome! d
base case
23
Example 1 Recursive palindrome
Yes! bacdcab is 0 1 2 3 4 5 6
a palindrome! b a c d c a b
Yes! acdca is a 0 1 2 3 4
palindrome!
a c d c a
Reuse of
answer of
smaller Yes! cdc is a 0 1 2
palindrome!
problem c d c
Yes! d is a 0
palindrome! d
base case
24
Example 1 Recursive palindrome
Ok, the first and the last slots are the same. No! bacdkab is 0 1 2 3 4 5 6
I want to ask if acdka is a palindrome? NOT a
palindrome! b a c d k a b
Ok, the first and the last slots are the same. No! acdka is NOT 0 1 2 3 4
I want to ask if cdk is a palindrome? a palindrome!
a c d k a
The first and the last slots are NOT the No! cdk is NOT a 0 1 2
same. palindrome!
c d k
25
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case
return True
else: # Progress
if s[0] == s[-1]:
return isPalindrome(s[1:-2])
else:
return False
Recursive approach Base case
If length of the string is less than
or equal to 1, that must be a
palindrome.
26
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case
return True
else: # Progress
if s[0] == s[-1]:
return isPalindrome(s[1:-2])
else:
return False
Recursive approach Not a palindrome
If the string’s first character is NOT
equal to the last one, immediately
conclude that it is NOT a
palindrome. 27
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case
return True
else: # Progress
if s[0] == s[-1]: s[1:-1] = a substring of s, starting
return isPalindrome(s[1:-1]) from index 1 and stopping at
else: index (-1 – 1 = -2)
return False
Recursive approach Progress towards base case
If the first and last slots of the
string are the same, then whether
the current string is a palindrome
depends on whether the internal
string is a palindrome. 28
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case
Now, let’s try to
return True
else: # Progress simulate what will
if s[0] == s[-1]: happen when we
return isPalindrome(s[1:-1])
run this program.
else:
return False
29
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case More importantly,
return True understand how return
else: # Progress isPalindrome(s[1:-2])
if s[0] == s[-1]: works in propagating
return isPalindrome(s[1:-1]) the result back the
else: recursive calls.
return False
31
Example 1 Recursive palindrome
def isPalindrome(s):
if len(s)<=1: # Base case
return True
else: # Progress
if s[0] == s[-1]:
return isPalindrome(s[1:-1])
else:
return False
If x can divide 105 and 504 Do you still remember how to solve
x can also divide 84 because: GCD(a,b)?
Rather than keeping on replacing the
84+(105*4)=504 larger number by the difference
between the two numbers until the
Therefore x can also x can divide x can divide
3 2 1 two numbers are the same, we can
divide this part this part this part
use remainder calculation.
33
Example 2. Greatest Common Divisor
Find the greatest common divisor (GCD) of two numbers, which is the
largest number that divides both of them without leaving a remainder.
GCD (504,105) = GCD (504%105, 105)
= GCD (84,105)
Let’s always rearrange the smaller
= GCD (105,84) value to be the 2nd parameter
= GCD (84,105%84)
= GCD (84,21)
= GCD (21,84%21)
= GCD (21,0) GCD(x,0) = x because
only x can divide x and 0.
= 21 34
Example 2. Greatest Common Divisor
Question 2. What
Base cases: is/are the base
If n<2, the case(s) that the
answer is n solution is readily
available? 38
Example 3. Fibonacci number
The Fibonacci numbers are the numbers in an integer sequence, called
the Fibonacci sequence, and characterized by the fact that every number
after the first two is the sum of the two preceding ones.
0 1 2 3 4 5 6 7 8 9 10 11 12
Fibonacci sequence …
0 1 1 2 3 5 8 13 21 34 55 89 144
Question 3. What is
Progress:
the progress to
To find the nth Fibonacci number,
break down the
we need to have the n-1th and
problem and reuse
the n-2th Fibonacci number first,
the solution of the
and sum them up.
smaller problem?
39
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
40
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
Now, let’s try to
f(4) f(3)
simulate what will
f(3) f(2) f(2) f(1)
happen when we
f(2) f(1) f(1) f(0) f(1) f(0) run f(5).
f(1) f(0)
41
Recursive calls
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
This is how the
f(4) f(3)
return from base
f(3) f(2) f(2) f(1)
case propagate back
1 f(1) f(1) f(0) f(1) f(0) to the parent calls.
1 0
f(5)
f(4) f(3)
43
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
f(4) f(3)
2 1 f(2) f(1)
1 0 f(1) f(0)
44
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
3 f(3)
2 1 f(2) f(1)
f(1) f(0)
45
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
3 f(3)
1 f(1)
1 0
46
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
f(5)
3 2
1 1
47
Example 3. Fibonacci number
def f(n):
if n<2: #Base case
return n
else: #Progress
return f(n-1)+f(n-2)
5 And finally, we
3 2 found that f(5) =
5, do you observe
Observation: There are any efficiency
many repeat function problem in the
calls! I try to call f(100), computation?
it is extremely slow! 48
Section 6.2
Memorization
Example 3. Fibonacci number
Implement a map that caches the computed Fibonacci numbers and avoid
repeat function calls.
cache = {} # Create a global map
def f(n):
if n in cache:
return cache[n] A global map object
if n<2: cache is a variable referencing a map
value = n object, which is initially empty.
else: The map will have key as the value of n,
value = f(n-1)+f(n-2) value storing the nth Fibonacci number.
cache[n] = value
return value 50
Example 3. Fibonacci number
Implement a map that caches the computed Fibonacci numbers and avoid
repeat function calls.
cache = {} # Create a global map
def f(n):
if n in cache:
return cache[n] Check if f(n) has been computed
if n<2: If n is in cache, then it has been
value = n computed before and we can directly
else: return its cached value without need of
value = f(n-1)+f(n-2)
recursive calls.
cache[n] = value
return value 51
Example 3. Fibonacci number
Implement a map that caches the computed Fibonacci numbers and avoid
repeat function calls.
cache = {} # Create a global map
def f(n):
if n in cache:
return cache[n] If not cached, compute recursively
if n<2: If n is NOT in cache, then we need to
value = n recursively compute its value.
else:
value = f(n-1)+f(n-2)
cache[n] = value
return value 52
Example 3. Fibonacci number
Implement a map that caches the computed Fibonacci numbers and avoid
repeat function calls.
cache = {} # Create a global map
def f(n):
if n in cache:
return cache[n] Update the cache
if n<2: Up to this point the value of the nth
value = n Fibonacci number has been computed,
else: we update the cache to store the newly
value = f(n-1)+f(n-2)
computed number.
cache[n] = value
return value 53
Example 3. Fibonacci number
Now, let’s try to simulate what
will happen when we run f(5).
cache[n] = value 1 0
return value 55
Example 3. Fibonacci number
f(2) = 1 is computed and
stored in the cache.
cache = {} # Create a global map Key 0 1 2
Cache
value 0 1 1
def f(n):
if n in cache: f(5)
return cache[n]
f(4) f(3)
if n<2:
value = n f(3) f(2)
else:
value = f(n-1)+f(n-2) f(2) f(1)
cache[n] = value 1 0
return value 56
Example 3. Fibonacci number
Cache hit! f(1) has computed before, so
its value, i.e.,1, is returned right away.
cache[n] = value
return value 57
Example 3. Fibonacci number
f(3) = 2 is computed and
stored in the cache.
cache = {} # Create a global map Key 0 1 2 3
Cache
value 0 1 1 2
def f(n):
if n in cache: f(5)
return cache[n]
f(4) f(3)
if n<2:
value = n f(3) f(2)
else:
value = f(n-1)+f(n-2) 1 1
cache[n] = value
return value 58
Example 3. Fibonacci number
Cache hit! f(2) has computed before, so
its value, i.e.,1, is returned right away.
cache[n] = value
return value 59
Example 3. Fibonacci number
f(4) = 3 is computed and
stored in the cache.
cache = {} # Create a global map Key 0 1 2 3 4
Cache
value 0 1 1 2 3
def f(n):
if n in cache: f(5)
return cache[n]
f(4) f(3)
if n<2:
value = n 2 1
else:
value = f(n-1)+f(n-2)
cache[n] = value
return value 60
Example 3. Fibonacci number
Cache hit! f(3) has computed before, so its
value, i.e.,2, is returned right away.
cache[n] = value
return value 61
Example 3. Fibonacci number
Obviously it is the
number of items in
the list, say n.
E.g., n=8 in this
17 26 31 44 54 55 77 93 example.
63
Example 4. MergeSort
54 26 93 17 77 31 44 55
54 26 93 17 77 31 44 55 Divide
Divide the list with n items to two
54 26 93 17 77 31 44 55 lists of n/2 items and sort them
54 26 93 17 77 31 44 55
54 26 93 17 77 31 44 55
26 54 17 93
Given two sorted lists of size n/2,
Compare 26 & 17, insert 17 to a new list. merging the two lists to create a
Compare 26 & 93, insert 26 to the new list.
Compare 54 & 93, insert 54 to the new list.
Finally, insert 93 to the new list.
sorted list of size n requires
The new list contains 17, 26, 54, 93.
Done!
scanning the two lists once only.
65
Example 4. MergeSort
54 26 93 17 77 31 44 55
54 26 93 17 77 31 44 55 Divide
Divide the list with n items to two
54 26 93 17 77 31 44 55 lists of n/2 items and sort them
54 26 93 17 77 31 44 55
26 54 17 93 31 77 44 55
Merge
17 26 54 93 31 44 55 77 Merge two sorted lists of size n/2 to
create a sorted list of n items
17 26 31 44 54 55 77 93
66
Example 4. MergeSort def mergeSort(A,left,right):
mergeSort(A,0,8)
if right-left>1:
54 26 93 17 77 31 44 55 mid = (left+right)//2
mergeSort(A, left, mid)
mergeSort(A, mid, right)
mergeSort(A,0,4) mergeSort(A,4,8) merge(A, left, mid, right)
54 26 93 17 77 31 44 55
A = [54,26,93,17,77,31,44,55]
mergeSort(A,0,len(A))
mergeSort(A,0,2) mergeSort(A,2,4) mergeSort(A,4,6) mergeSort(A,6,8)
54 26 93 17 77 31 44 55 right-left > 1 is a
condition to detect
mergeSort mergeSort mergeSort mergeSort mergeSort mergeSort mergeSort mergeSort
(A,0,1) (A,1,2) (A,2,3) (A,3,4) (A,4,5) (A,5,6) (A,6,7) (A,7,8) progress cases.
54 26 93 17 77 31 44 55
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=0
i=i+1
k=k+1
R 31 44 55 77 j=0
while j < len(R):
A[k]=R[j]
j=j+1
k=k+1
69
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 54 93 31 44 55 77 k=0
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=0
i=i+1
k=k+1
R 31 44 55 77 j=0
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
70
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 54 93 31 44 55 77 k=1
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=1
i=i+1
k=k+1
R 31 44 55 77 j=0
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
71
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 93 31 44 55 77 k=2
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=2
i=i+1
k=k+1
R 31 44 55 77 j=0
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
72
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 44 31 44 55 77 k=3
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=2
i=i+1
k=k+1
R 31 44 55 77 j=1
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
73
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 44 54 44 55 77 k=4
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=2
i=i+1
k=k+1
R 31 44 55 77 j=2
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
74
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 44 54 55 55 77 k=5
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=3
i=i+1
k=k+1
R 31 44 55 77 j=2
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
75
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 44 54 55 77 77 k=6
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=3
i=i+1
k=k+1
R 31 44 55 77 j=3
while j < len(R):
A[k]=R[j]
j=j+1 This part just put the smallest value
k=k+1 among L and R to A, one at a time.
76
def merge(A,left,mid,right):
L = A[left:mid] merge(A,0,4,8)
R = A[mid:right]
i=j=0
k=left k
while i < len(L) and j < len(R):
if L[i] < R[j]: A 17 26 31 44 54 55 77 93 k=7
A[k]=L[i]
i=i+1
k=k+1 Sorted Sorted
else:
A[k]=R[j] i
j=j+1
k=k+1 L 17 26 54 93 i=3
i=i+1
k=k+1
R 31 44 55 77 j=4
while j < len(R):
A[k]=R[j]
Since all values in R are scanned,
j=j+1
we put the remaining values in L to A.
k=k+1
77
Example 5. Tower of Hanoi
n=4
A B C
The Tower of Hanoi is a mathematical game.
It consists of three rods (A,B,C) and n disks of different sizes which can slide
onto any rod.
Constraint: At any stage, no larger disk can be placed on top of smaller disk.
The objective of the puzzle is to move the entire stack from rod A to rod C.
Only one disk is allowed to move at a time. 78
Example 5. Tower of Hanoi
n=1
A B C
79
Example 5. Tower of Hanoi
n=2
A B C
80
Example 5. Tower of Hanoi
n=2
A B C
81
Example 5. Tower of Hanoi
n=2
A B C
82
Example 5. Tower of Hanoi
n=2
A B C
83
Example 5. Tower of Hanoi
n=3
A B C
A B C
85
Example 5. Tower of Hanoi
Problem
for n = 2
n=2
A B C
86
Example 5. Tower of Hanoi
Problem
for n = 2
n=2
A B C
87
Example 5. Tower of Hanoi
Problem
n=3 for n = 3
A B C
88
Example 5. Tower of Hanoi
Problem
n=3 for n = 3
A B C
89
Example 5. Tower of Hanoi
Problem
n=3 for n = 3
A B C
90
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1,from, buffer, to)
move(1,from, to, buffer)
moveTower(n-1, buffer, to, from)
Base case:
Just move the disk from
the fromPole to the toPole
when height==1.
91
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end)
move(1, start, end, buffer)
move(n-1, buffer, end, start)
Progress:
Make a n-1 problem to move the tower from start to buffer.
Make a 1 problem to move the tower from start to end.
Make a n-1 problem to move the tower from buffer to end.
92
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end)
move(1, start, end, buffer)
move(n-1, buffer, end, start)
move(2,"A","B","C")
move(3,"A","C","B")
94
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case move(1,"A","C","B")
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end) move(1,"A","B","C")
move(1, start, end, buffer)
move(n-1, buffer, end, start)
move(1,"C","B","A")
move(2,"A","B","C")
move(3,"A","C","B")
95
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case move(1,"A","C","B")
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end) move(1,"A","B","C")
move(1, start, end, buffer)
move(n-1, buffer, end, start)
move(1,"C","B","A")
move(2,"A","B","C")
move(1,"A","C","B")
move(3,"A","C","B")
96
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case move(1,"A","C","B")
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end) move(1,"A","B","C")
move(1, start, end, buffer)
move(n-1, buffer, end, start)
move(1,"C","B","A")
move(2,"A","B","C")
move(1,"A","C","B")
move(3,"A","C","B")
move(2,"B","C","A")
97
Example 5. Tower of Hanoi
def move(n, start, end, buffer):
if n == 1: # Base case move(1,"A","C","B")
print("Moving disk from",start,"to",end)
else: # Progress
move(n-1, start, buffer, end) move(1,"A","B","C")
move(1, start, end, buffer)
move(n-1, buffer, end, start)
move(1,"C","B","A")
move(2,"A","B","C")
move(1,"B","A","C")
move(1,"A","C","B")
move(3,"A","C","B")
move(1,"B","C","A")
move(2,"B","C","A")
move(1,"A","C","B")
98
Example 5. Tower of Hanoi
1
Now, let’s try to use these 7 steps to see if move(1,"A","C","B")
you can solve the Tower of Hanoi problem 2
with n=3? move(1,"A","B","C")
Let’s try move(4,"A","C","B") as
3
well!
move(1,"C","B","A")
move(2,"A","B","C")
5
4 move(1,"B","A","C")
move(1,"A","C","B")
move(3,"A","C","B") 6
move(1,"B","C","A")
7
move(2,"B","C","A")
move(1,"A","C","B")
99
Example 5. Tower of Hanoi
A B C
100
Summary
To understand recursive strategy, you need to know…
The parameter that determines the problem size.
The base case(s) where the solution is readily available.
The progress to break down a bigger problem to smaller problem(s).
The strategy to reuse the solutions of the smaller problem(s) to solve the
bigger problem.
101
102
Chapter 6.
END
Acknowledgement:
This set of slides is partially adopted from
ENGG1330. Thanks to Dr. C.K. Chui!
2024-2025
COMP1117A Computer Programming
Dr. T.W. Chim ([email protected]) & Dr. H.F. Ting ([email protected])
Department of Computer Science, The University of Hong Kong