Recursion
Minh Ngo
1 Definitions
Definition 1. Reduction is a technique to reduce a problem X to a problem Y that we already have an algorithm
to solve.
Definition 2. Recursion is a kind of reduction, which can be described as:
• If the given instance of the problem can be solved directly, solve it directly.
• Otherwise, reduce it to one or more simpler instance(s) of the same problem. This is analogous to induction
hypothesis in mathematics.
Definition 3. A function which calls itself directly or indirectly is a recursive function .
In a recursive program, the solution to the base case is provided and the solution of the bigger problem is
expressed in terms of smaller problems. A typical recursive algorithm can be expressed in pseudocode as following:
Algorithm 1 Recursion
1: procedure Recursion (case)
2: if Base case then
3: return solution of base case
4: else
5: return Recursion(subcase(s))
6: end if
7: end procedure
2 Examples
2.1 Peasant multiplication
Peasant multiplication algorithm is based on the following simple identity:
0
if x=0
x · y = 2 · bx/2c · y if x is even
2 · bx/2c · y + y x is odd
if
So we can multiply x and y by multiplying x0 and y 0 , then may be add y to the result (if x is odd). This
multiplication is simpler since x0 < x, and if we keep decreasing x, we will eventually get to 0. We can express the
process algorithmically as follow.
1
Algorithm 2 Peasant multiplication
1: procedure Multiply x, y ( )
2: if x=0 then
3: return 0
4: else
5: prod ← 2 · Multiply(bx/2c, y) . Recurse
6: if x is odd then
7: prod ← prod + y
8: end if
9: return prod
10: end if
11: end procedure
An implementation of the above algorithm in C.
# include < stdio .h >
int multiply ( int x , int y) {
if (x == 0) return 0;
int prod = 2 * multiply (x / 2, y) ;
if (x & 1) return prod + y ;
return prod ;
}
int main () {
printf ("%d \n" , multiply (6 , 5) );
}
An implementation of the above algorithm in Python.
def multiply (x , y):
if x == 0: return 0
prod = 2 * multiply ( x // 2, y)
if x & 1: return prod + y
return prod
print ( multiply (6 , 5) )
2.2 Calculate power
When we replace the addition with the multiplication and the multiplication with the power in the multiply
algorithm above, we will receive a recursive algorithm to calculate power.
The identity for power is similar:
1
2
if y=0
y
x = xby/2c if y>0 and y even
by/2c 2
x ·x if y>0 and y odd
y
So we can calculate x by taking the power y/2 of x, then take it square and may be multiply y. This problem
is simpler, and if we keep decreasing y, we will get to base case y = 0. Algorithmically, the identity looks like this.
Algorithm 3 Binary power
1: procedure Power x, y( )
2: if y=0 then
3: return 1
4: else
5: pow ← Power(x, by/2c) . Recurse
6: if y is odd then
7: pow ← pow · x
8: end if
9: return pow
10: end if
11: end procedure
2
An implementation of the above algorithm in C.
# include < stdio .h >
long long power ( int x , int y ) {
if (y == 0) return 1;
long long pow = power (x , y / 2) ;
if (y & 1) return pow * pow * 1 ll * x;
else return pow * pow ;
}
int main () {
printf ("% lld \n " , power (6 , 5) ) ;
}
An implementation of the above algorithm in Python.
def power (x , y):
if y == 0: return 1
pwr = power (x , y // 2)
if y & 1: return pow ** 2 * x
return pow ** 2
print ( pow (6 , 5) )
2.3 Calculate factorial
The algorithm for factorial makes use of this simple identity
n! = (n − 1)! · n
So to calculate n!, we just need to calculate (n−1)! and the multiply the result with n. And when we keep decreasing
n, we will eventually reach base case 0! = 1.
Algorithm 4 Calculate factorial
1: procedure Fact x ( )
2: if x=0 then
3: return 1
4: else
5: return x· Fact (x − 1) . Recurse
6: end if
7: end procedure
An implementation of the above algorithm in C. Note that in C, we can only calculate small factorial using
built-in data type. If we want to calculate large factorial, we have to use Python or write an ad hoc multiplication
of a large number and a small number, which we will discuss in a different note.
# include < stdio .h >
long long fact ( int x) {
if (x == 0) return 1;
else return 1 ll * x * fact ( x - 1) ;
}
int main () {
printf ("% lld \n " , fact (15) );
}
An implementation of the above algorithm in Python.
def fact (x):
if x == 0: return 1
return x * fact (x - 1)
print ( fact (6) )
3
2.4 Calculate Fibonacci numbers
The Fibonacci sequence (fn ) is defined as following:
(
1 if n = 0, 1
fn =
fn−1 + fn−2 if n ≥ 2.
Important note: Every sequenced that is defined by recursive identity like this is susceptible to recursion.
The pseudocode for Fibonacci algorithm:
Algorithm 5 Calculate Fibonacci numbers
1: procedure Fibo x
( )
2: if x≤1 then
3: return 1
4: else
5: return Fibo (x − 1) + Fibo (x − 2) . Recurse
6: end if
7: end procedure
An implementation of the above algorithm in C.
# include < stdio .h >
int fibo ( int n) {
if (n <= 1) return 1;
return fibo (n - 1) + fibo (n - 2) ;
}
int main () {
printf ("% lld \n " , fibo (5) ) ;
}
An implementation of the above algorithm in Python.
def fibo (x):
if x <= 1: return 1
return fibo (x - 1) + fibo (x - 2)
print ( fibo (6) )
2.5 Calculate binomial coefficients
n
Binomial coefficients
k are the number of ways to select a set of k elements from n different elements without
taking into account the order of arrangement of these elements (i.e., the number of unordered sets).
To calculate binomial coefficient, the first method is to use the analytic formula
n n!
=
k k!(n − k)!
This formula can be easily deduced from the problem of ordered arrangement (number of ways to select k different
elements from n different elements). The second way is to use the recurrence formula, discovered by Pascal:
n n−1 n−1
= +
k k−1 k
It is easy to deduce this using the analytic formula.
n
Note that for n < k, the value of
k is assumed to be 0.
Using the recurrence formula, we have the following algorithm:
4
Algorithm 6 Calculate binomial coefficients
1: procedure Binom n, k ( )
2: if n<k then
3: return0
4: else if k=0 or k=n then
5: return 1
6: else
7: return Binom (n − 1, k − 1) + Binom (n − 1, k) . Recurse
8: end if
9: end procedure
An implementation of the above algorithm in C.
# include < stdio .h >
int binom ( int n , int k) {
if (n < k) return 0;
if (k == 0 || k == n) return 1;
return binom (n - 1, k - 1) + binom ( n - 1, k);
}
int main () {
printf ("% lld \n " , binom (5 , 3) ) ;
}
An implementation of the above algorithm in Python.
def binom (n , k):
if n < k : return 0
if k == 0 or k == n: return 1
return binom (n - 1, k - 1) + binom ( n - 1, k)
print ( binom (5 , 3) )
2.6 Length of Collatz sequences
The infamous Collatz's conjecture stated as following: Given a positive integer x, we keep do the following operation
(
x
2 if x is even
x=
3x + 1 if x is odd
then after a finite number of operations, we will arrive at 1. Now, if we assume that the conjecture is actually
correct, we want to compute the number of operations that will reduce x to 1.
Now, letc(n) denote the number of such operations. Then if n is even, we have c(n) = c(n/2) + 1 and if n is
odd, we have c(n) = c((3n + 1)/2) + 2. This gives us the following algorithm:
Algorithm 7 Length of Collatz sequence
1: procedure Collatz n ( )
2: if n=1 then
3: return 0
4: else if n is even then
5: return Collatz (n/2) + 1 . Recurse
6: else
7: return Collatz ((3n + 1)/2) + 2 . Recurse
8: end if
9: end procedure
An implementation of the above algorithm in C.
# include < stdio .h >
int collatz ( int n) {
if (n == 1) return 0;
5
else if ( n & 1) return collatz ((3 * n + 1) / 2) + 2;
return collatz (n / 2) + 1;
}
int main () {
printf ("% lld \n " , collatz (13) ) ;
}
An implementation of the above algorithm in Python.
def collatz ( n):
if n == 1: return 0
elif n & 1: return collatz ((3 * n + 1) // 2) + 2
return collatz (n // 2) + 1
print ( collatz (13) )
2.7 Tower of Hanoi
This infamous problem was first published by Eduouard Lucas is 1883. The puzzle can be described as following:
The puzzle consists of three rods and a number of disks of different sizes, which can slide onto any rod.
The puzzle starts with the disks in a neat stack in ascending order of size on one rod, the smallest at
the top, thus making a conical shape.
The objective of the puzzle is to move the entire stack to another rod, obeying the following simple
rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the upper disk from one of the stacks and placing it on top of another
stack or on an empty rod.
3. No larger disk may be placed on top of a smaller disk
H¼nh 1: The Tower of Hanoi puzzle
The crux to solving this puzzle is to solve it recursively. So instead of trying to solve the entire puzzle at once,
we will solve it recursively. First, we try to moving just the largest disk. We can't move it at the beginning, because
all the other disks are in the way. So first we have to move those n − 1 disks to a spare peg. And then after we move
the largest disk, we have to move those n − 1 disks back on top of it. So now, the problem reduces to solving two
instances of the same problem with n − 1. The base case is when n = 0, we have to do nothing at all.
Using this recursive scheme, we have the following recurrence relation for the number of steps we need to solve
this puzzle. Let cn be the number of steps we need to solve this puzzle for n disks, then cn = 2cn−1 + 1. It's easy
to see from this recurrence relation that the general formula is 2n − 1, and we can prove this easily with induction.
Pseudocode for algorithm to solve the puzzle
Algorithm 8 Tower of Hanoi
1: procedure Hanoi n, src, dst, tmp
( )
2: if n>0 then
3: Hanoi(n − 1, src, tmp, dst) . Recurse
4: move diskn from src to dst
5: Hanoi(n − 1, tmp, dst, src) . Recurse
6: end if
7: end procedure
6
An implementation by Python can be found below.
A = [3 , 2 , 1]
B = []
C = []
def hanoi (n , src , dst , tmp ) :
if n > 0:
hanoi (n - 1 , src , tmp , dst )
dst . append ( src . pop () )
print (A , B , C , ' ######### ', sep = '\ n ')
hanoi (n - 1 , tmp , dst , src )
hanoi (3 , A , B , C)