0% found this document useful (0 votes)
32 views43 pages

16 - Recursion 1

Uploaded by

adjanarcamara
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views43 pages

16 - Recursion 1

Uploaded by

adjanarcamara
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

COMP 250

INTRODUCTION TO COMPUTER SCIENCE


16 - Recursion 1

Giulia Alberini, Fall 2024


ANNOUNCEMENTS

 After today's class you'll receive an email from the MILES lab
with a link to a short survey. This is the last of the end-of-class
surveys! Please take few minutes to fill it out.
WHAT ARE WE GOING TO DO TODAY?

 Recursive algorithms
 reverseList
 sortList
 towerOfHanoi
 power
RECURSIVE – DEFINITION

Recursive functions/methods consists of the following

 Base Case(s): one (or a finite number) of terminating


scenario that does not use recursion to produce an answer.

 Recursive or Inductive step(s): rules that determine how


to produce an answer from simpler cases.
FIRST EXAMPLE

public static void spookyCountdown(int n) {


if (n == 0) {
System.out.print(“Boo!”);
} else {
System.out.print(n + “ ”);
spookyCountdown (n-1);
}
}

 What prints if we call spookyCountdown(3)?


 3 2 1 Boo!
THINK-PAIR-SCARE (5-10 MIN)

We would like two recursive algorithms that:


1. Reverse a list
2. Sort a list

Let's take few minutes to think about it!


1. First think of a possible solution yourself
2. Pair up and discuss your ideas
3. Share with the rest of the class!
EXAMPLE 3 - REVERSING A LIST (RECURSIVE)

public static void reverse(List list) {


if(list.size()==1) {
return;
}
firstElement = list.remove(0); // remove first element
reverse(list); // now the list has n-1 elements
list.add(firstElement); // appends at the end of the list
}
EXAMPLE 4 – SORTING A LIST (RECURSIVE)

public static void sort(List list) {


if(list.size()==1) {
return;
}
minElement = removeMinElement(list);
sort(list); // now the list has n-1 elements
list.add(0, minElement); // insert at the beginning of list
}
RECURSION – COMMON MISTAKES

When debugging your code look for the following common mistakes:
 You forget to handle the base case, or one of the base cases.
 The recursive step does not reduce the problem to a smaller one, hence the
recursion does not converge (i.e. the base case cannot be reached)

On the bright side, if you write a program that has an infinite recursion, then a
StackOverflowError will be raised. A buggy recursive program fails faster
than one with an infinite iteration.
EXAMPLE 5 – TOWER OF HANOI

Tower A Tower B Tower C


(start) (finish)

Problem: Move n disks from start tower to finish tower such that:

- move one disk at a time

- you can have a smaller disk on top of bigger disk (but you can’t
have a bigger disk onto a smaller disk)
EXAMPLE - n=1

start finish

start finish
EXAMPLE - n=2

start finish

from A to C

start finish
EXAMPLE - n=2
from A to B

start finish

from C to B

start finish
HOW SHOULD WE MOVE 5 DISKS FROM A TO B?

start finish

 Let’s think about it recursively!


IDEA!
Somehow move 4 disks from A to C

move 1 disk from A to B

Somehow move 4 disks from C to B


ALGORITHM

tower(n, start, finish, other) { // e.g. tower(5,A,B,C)


if(n==1) {
move from start to finish.
} else {
tower(n-1, start, other, finish)
tower(1, start, finish, other)
tower(n-1, other, finish, start)
}
}
EXAMPLE
tower(4,A,C,B)

tower(1,A,B,C)

tower(4,C,B,A)
CORRECTNESS

Claim: the tower( ) algorithm is correct, namely it moves the blocks from start to
finish without breaking the two rules (one at a time, and can’t put bigger one onto
smaller one).
Proof: (sketch)
 Base case: tower(1,*,*,*) is correct.
 Induction step:
 for any k > 1, assume tower(k,*,*,*) is correct
 Prove tower(k+1,*,*,*) is correct.
HOW MANY MOVES?

tower(1, start, finish, other )

move from
start to finish

Answer: 1
HOW MANY MOVES?

tower( 2, start, finish, other )

tower( 1, start, other, finish) move tower( 1, other, finish, start )

move move

move from A to C

Answer: 1+2 move from A to B

move from C to B
HOW MANY MOVES?

tower( 3, start, finish, other )

tower( 2, start, other, finish) move tower( 2, other, finish, start )

move move

move move move move

Answer: 1 + 2 + 4 = 20 + 21 + 22
HOW MANY MOVES?

tower( n, start, finish, other )

tower( n – 1, start, other, finish) move tower( n – 1, other, finish, start )

move move

… move … … move … … move … … move …

Answer: 1 + 2 + 4 + … + 2𝑛−1 = 2𝑛 − 1
RECURSION AND ITERATION

 Recursion and iteration (loops) are equally expressive.


 Anything recursion can do, iteration and do
 Anything iteration can do, recursion can do
RECURSION VS ITERATION

 Which one to use?


 Use the one is easier to think in terms of, for a specific
problem.
 For simple cases, iteration is usually easier and faster.
 For complex cases, recursion is often more elegant and
simpler to code.
 It is important to remember that when using one or the
other, this decision might impact the performance of your
program.
LET'S SOLVE A RECURSIVE MYSTERY
Consider a data type Item from which a non-static method called use() has been
defined. Consider also, the method useBagOfTricks() which receives as input a
stack of items. The method goes through all of them, uses them, and then stores
them back into the stack in the same order. Write a recursive version of this method.

public static void useBagOfTricks(Stack<Item> tricks) {


Stack<Item> items = new Stack<Items>();
while (! tricks.empty()) {
Item i = tricks.pop();
i.use();
items.push(i);
}
while (! items.empty() ) {
tricks.push(items.pop());
}
}
POWER (𝑥𝑛) – DEFINITION

 Definition of power
𝑥𝑛 = 𝑥 ⋅ 𝑥 ⋯ 𝑥
𝑛 times

 Inductive definition:
 Base clause:
𝑥0 = 1
 Inductive clause:
𝑥 𝑛 = 𝑥 ⋅ 𝑥 𝑛−1
POWER (𝑥𝑛) – ITERATIVE 1

Let 𝑥 be a positive integer and let 𝑛 be a positive number.

power(x, n) {
int result =1;
for(int i=1; i<=n; i++) {
result = result * x;
}
return result;
}
POWER (𝑥𝑛) – RECURSIVE

power(x, n) {
if(n==0) {
return 1;
} else {
return x * power(x,n-1);
}
}
POWER() – CAN WE DO BETTER?

More interesting approach using recursion:

18 9 9
𝑥 = 𝑥 ∗𝑥
9 4 4
𝑥 = 𝑥 ∗𝑥 ∗𝑥
𝑥4 = 𝑥2 ∗ 𝑥2
2
𝑥 = 𝑥∗𝑥
POWER (𝑥𝑛) – RECURSIVE 2

power( x, n) {
if (n == 0)
return 1;
else if (n == 1)
return x;
else{
tmp = power(x, n/2);
if (n%2==0)
return tmp*tmp; // one multiplication
else
return tmp*tmp*x; // two multiplications
}
}
A SIMILAR IDEA CAN BE IMPLEMENTED ITERATIVELY

IDEA: Let’s use the binary expansion of 𝑛, say 𝑛 = 𝑎𝑘−1 , … , 𝑎1 , 𝑎0 2 .


Note that:
𝑘−1 +⋯+𝑎 2+𝑎 𝑘−1
𝑥𝑛 = 𝑥 𝑎 𝑘−1 2 1 0 = 𝑥 𝑎 𝑘−1 2 ⋯ 𝑥 𝑎1 2 ⋅ 𝑥 𝑎0
This shows how to compute 𝑥 𝑛 : we only need to compute the values
𝑘
of 𝑥, 𝑥 2 , 𝑥 2 2 = 𝑥 4 , … , 𝑥 2 . Once we have these terms we multiply the
𝑗
terms 𝑥 , where
2 𝑎𝑗 = 1.
POWER (𝑥𝑛) – ITERATIVE 2

power(x, n) {
result = 1;
pow = x; Let 𝑛 = 𝑎𝑘−1 , … , 𝑎1 , 𝑎0 2
if(n%2 == 1)
result = x;
n = n/2;
while(n != 0) { // log 2 (𝑛) − 1 iterations
pow = pow * pow; // 1 multiplication
if(n%2 == 1)
result = result * pow; // 1 multiplication
n = n/2;
}
return result;
}
POWER (𝑥𝑛) – ITERATIVE 2

power(x, n) {
result = 1;
pow = x; Let 𝑛 = 𝒂𝒌−𝟏 , … , 𝒂𝟏 , 𝒂𝟎 2
if(n%2 == 1)
result = x;
n = n/2;
while(n != 0) { // log 2 (𝑛) − 1 iterations
pow = pow * pow; // 1 multiplication
if(n%2 == 1)
result = result * pow; // 1 multiplication
n = n/2;
}
return result;
}
POWER (𝑥𝑛) – ITERATIVE 2

power(x, n) {
result = 1;
pow = x; Let 𝑛 = 𝒂𝒌−𝟏 , … , 𝒂𝟏 , 𝑎0 2
if(n%2 == 1)
result = x;
n = n/2;
while(n != 0) { // log 2 (𝑛) − 1 iterations
pow = pow * pow; // 1 multiplication
if(n%2 == 1)
result = result * pow; // 1 multiplication
n = n/2;
}
return result;
}
EXAMPLE: 𝑥243

𝑛 = (243)10 = (11110011)2

Q: How many multiplications do we need?


EXAMPLE: 𝑥243

𝑛 = (243)10 = (11110011)2

Q: How many multiplications do we need?

A: Recursive method: 5*2 + 2*1 = 12.


Iterative method: 7 + 5 = 12

The highest order bit in the recursive method is the base


case, and doesn’t require a multiplication.
The lowest order bit in the iterative method does not require
multiplication.
EXAMPLE: 𝑥243

𝑛 = (243)10 = (11110011)2

Q: How many multiplications do we need?

A: 𝑂(log 𝑛)
OBSERVATIONS

The second approach we looked at uses fewer multiplications than the


first one, and thus the second approach seems faster.

Q: Is this indeed the case?

A: No. Why not ?


OBSERVATIONS

Hint: Let 𝑥 be a positive integer with M digits.

 𝑥 2 has about ? digits.


 𝑥 3 has about ? digits.
 :
 𝑥 𝑛 has about ? digits.
OBSERVATIONS

Hint: Let 𝑥 be a positive integer with M digits.

 𝑥 2 has about 2M digits.


 𝑥 3 has about 3M digits.
 :
 𝑥 𝑛 has about 𝑛 ∗ M digits.
We cannot assume that multiplication takes ‘constant’ time.
Taking large powers gives very large numbers and
multiplications becomes more expensive.
LET'S SOLVE ANOTHER RECURSIVE MYSTERY

We can recursively define also data structures. Consider the following class
defining a Spell recursively. Each spell has a title and an optional list of subspells
within it. Write a recursive method reciteSpell() that takes a Spell as input
and prints the title of each spell and its subspells in the order they appear.

public class Spell {


public String title;
public List<Spell> subspells;

public Spell(String title) {…}

:
}
Coming next:
 Binary Search

You might also like