recursion - computer algorithms
TRANSCRIPT
Recursion
Alaa K. Al-Makhzoomy – Faculty of IT - WISE
1. Motivation
2
Suppose you want to find all the files under a directory that contains a particular word. How do you solve this problem?
There are several ways to solve this problem.
An intuitive solution is to
use recursion by searching
the files in the subdirectories
recursively.
2. Motivation
3
Try to solve the following
word game.
Reference:
https://www.pennydellpuzzles.com/Upload/PuzzleFiles/Sample/FillIns/fi001
_d0508_freepuz.pdf
3. Motivation – Solving Complex Problems
4
The Eight Queens puzzle consists on placing eight queens on a chessboard
such that no two queens are on the same row, same column, or same
diagonal, as shown in figure below.
Your turn: Try placing n Queens on an n*n board
Typical Example - Computing Factorial
5
Notation
n ! = n * (n-1)!
factorial( n ) = n * factorial( n-1 );
Example: Compute the value of 4!
factorial(4) = 4 * factorial( 3 )
= 4 * ( 3 * factorial(2) )
= 4 * ( 3 * (2 * factorial(1)) )
= 4 * ( 3 * ( 2 * (1 * factorial(0))))
= 4 * (3 * ( 2 * ( 1 * 1 )))
= 4 * (3 * ( 2 * 1))
= 4 * (3 * 2 )
= 4 * 6
= 24
Trace Recursive factorial
6
Main method
3
Space Required
for factorial(3)
Space Required
for factorial(2)
Space Required
for factorial(4)
4
Space Required
for factorial(3)
Space Required
for factorial(2)
Space Required
for factorial(1)
5 Stack
return 1
factorial(4)
return 4 * factorial(3)
return 3 * factorial(2)
return 2 * factorial(1)
return 1 * factorial(0)
Step 9: return 24 Step 0: executes factorial(4)
Step 1: executes factorial(3)
Step 2: executes factorial(2)
Step 3: executes factorial(1)
Step 5: return 1
Step 6: return 1
Step 7: return 2
Step 8: return 6
Step 4: executes factorial(0)
Recursive descend
Backtrack
Computing Factorial
private static int fact(int n) {
if ( n == 0 )
return 1;
else
return n*fact(n-1);
}
factorial(4) Stack Trace
8
Other Example – Recursive Summation
9
f(0) = 0;
f(n) = n + f(n-1);
Example:
f (12) = 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12
Observe that f(12) = 12 + f(11), and
f (11) = 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11
Which in turn can be computed as f(11) = 11 + f(10)
Likewise, f(10) = 10 + f(9), and so on, until f(0) = 0 is discovered
f(11)
f(10)
Recursive sum of first n numbers
1
00
nn
ini
Fibonacci Numbers
10
Fibonacci series: 0 1 1 2 3 5 8 13 21 34 55 89…
indices: 0 1 2 3 4 5 6 7 8 9 10 11
fib(0) = 0;
fib(1) = 1;
fib(index) = fib(index -1) + fib(index -2); index >=2
fib(3) = fib(2) + fib(1)
= (fib(1) + fib(0)) + fib(1)
= (1 + 0) +fib(1)
= 1 + fib(1)
= 1 + 1 = 2
Fibonacci Numbers
11
private static int fib(int n) {
if ((n == 1) || (n == 0))
return n;
else
return fib(n - 2) + fib(n - 1);
}
Fibonnaci Numbers, cont.
12
Fibonnaci Numbers.
13
Fibonacci Numbers
1 (Jan) C1 1 (Feb) C1 2 (Mar) C1 C1,1 3 (Apr) C1 C1,2 C1,1
5 (May) C1 C1,3 C1,2 C1,1 C1,1,1 8 (Jun) C1 C1,4 C1,3 C1,2 C1,2,1 C1,1 C1,1,2 C1,1,1 13 (Jul) 21 (Aug) 34 (Sep) 55 (Oct) 89 (Nov) 144 (Dec)
C x,y
Represents a couple of male & female rabbits.
C1,2 is the second offspring pair descending
from couple 1.
Fibonacci sequence first appears in the book Liber Abaci (1202) by Leonardo of Pisa, known as Fibonacci.
Fibonacci considers the growth of an idealized rabbit population, assuming that: a newly born pair of rabbits, one male, one female, are put in a field; rabbits are able to mate at the age of one month so that at the end of its second month a female can produce another pair of rabbits; rabbits never die and a mating pair always produces one new pair (one male, one female) every month from the second month on. The puzzle that Fibonacci posed was: how many pairs will there be in one year? Taken from: http://en.wikipedia.org/wiki/Fibonacci_number
Fibonnaci
Numbers.
14 Images from: mathacademy.com,
Fibonacci Spiral
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …
Known as “The fingerprint of God”
See an interesting video at (watch at your own risk!) http://www.youtube.com/watch?v=e9MwNm0gXd8
Characteristics of Recursion
15
All recursive methods have the following characteristics:
One or more base cases (the simplest case) are used to stop recursion
(boundary conditions). Every recursive call reduces the original problem, bringing it
increasingly closer to a base case until it becomes that case.
In general, to solve a problem using recursion,
1. you break it into subproblems. 2. If a subproblem resembles the original problem, you can apply the same approach to
solve the subproblem recursively. 3. This subproblem is almost the same as the original problem in nature with a smaller
size.
Problem Solving Using Recursion
16
Let us consider a simple problem of printing a message for n times.
You can break the problem into two subproblems:
1. One is to print the message one time and the other is to print the message for n-1 times.
2. The second problem is the same as the original problem with a smaller size.
3. The base case for the problem is n==0.
private static void printMsg(String msg, int times) {
// printing a message a number of times if (times==0) return; System.out.println(times + " " + msg); printMsg(msg, times-1);
}
private static boolean isPalindrome ( String str ) { if (str.length() == 0 || str.length() == 1) return true; char first = str.charAt(0); char last = str.charAt(str.length() - 1); if (first != last) return false; else { str = str.substring(1, str.length() - 1); return isPalindrome( str ); } }
Version1: Palindrome
17
Examples: 100a001, MADAMIMADAM, abccba are palindromes.
Version2: Recursive Helper Methods
18
Examples: 100a001, MADAMIMADAM, abccba are palindromes.
public static boolean isPalindrome(String s) {
return isPalindrome(s, 0, s.length() - 1);
}
public static boolean isPalindrome(String s, int low, int high) {
if (high <= low) // Base case
return true;
else if (s.charAt(low) != s.charAt(high)) // Base case
return false;
else
return isPalindrome(s, low + 1, high - 1);
}
Directory Size
19
This section presents a problem that is difficult to solve without using recursion.
The problem is to find the size of a directory. The size of a directory is the sum of the sizes of all files in the directory. A directory may contain subdirectories.
directory
...
1f
1
2f
1
mf
1
1d
1
2d
1
nd
1
...
)(...)()()(...)()()( 2121 nm dsizedsizedsizefsizefsizefsizedsize
Directory Size
20
public class DirectorySize {
public static void main(String[] args) {
System.out.print("Enter a file or a directory: ");
java.util.Scanner input = new java.util.Scanner(System.in);
String s = input.nextLine();
try {
System.out.println( directorySize( new File(s) ) );
}
catch (IOException ex) {
System.out.println(ex.toString());
}
}
public static long directorySize(File file) throws java.io.FileNotFoundException{
if (!file.exists())
throw new java.io.FileNotFoundException(file + " not found");
if (file.isFile()) {
return file.length();
}
else {
File[] files = file.listFiles();
long size = 0;
for (int i = 0; i < files.length; i++)
size += directorySize(files[i]);
return size;
}
}
}
Towers of Hanoi
21
There are n disks labeled 1, 2, 3, . . ., n, and three towers labeled
A, B, and C.
No disk can be on top of a smaller disk at any time.
All the disks are initially placed on tower A.
Only one disk can be moved at a time, and it must be the top disk
on the tower.
Invented by french
mathematician
Edouard Lucas (1842)
Image from Wikipedia 7/8/2011
Towers of Hanoi, cont.
22
A B
Original position
C A B
Step 4: Move disk 3 from A to B
C
A B
Step 5: Move disk 1 from C to A
C A B
Step 1: Move disk 1 from A to B
C
A C B
Step 2: Move disk 2 from A to C
A B
Step 3: Move disk 1 from B to C
C A B
Step 7: Mve disk 1 from A to B
C
A B
Step 6: Move disk 2 from C to B
C
Solution to Towers of Hanoi
23
The Towers of Hanoi problem can be decomposed into three subproblems.
A B
Original position
C
.
.
.
A B
Step 1: Move the first n-1 disks from A to C recursively
C
.
.
.
A B
Step2: Move disk n from A to C
C
.
.
.
A B
Step3: Move n-1 disks from C to B recursively
C
.
.
.
n-1 disks
n-1 disks
n-1 disks
n-1 disks
Step 2. Move disk n from A to B
Solution to Towers of Hanoi
24
1. Move the first n - 1 disks from A to C with the assistance of tower B.
2. Move disk n from A to B.
3. Move n - 1 disks from C to B with the assistance of tower A.
Solution to Towers of Hanoi
25
public static void main(String[] args) { int n = 4; // moving disks from A to B using C as auxiliary tower System.out.println("Towers of Hanoi. The moves are:"); moveDisks(n, 'A', 'B', 'C'); } private static void moveDisks( int n, char fromTower, char toTower, char auxTower) { if (n == 1) System.out.println("Move disk " + n + " from " + fromTower + " to " + toTower); else { moveDisks(n-1, fromTower, auxTower, toTower); System.out.println("Move disk " + n + " from " + fromTower + " to " + toTower); moveDisks(n-1, auxTower, toTower, fromTower); }
Greatest Common Divisor - GCD
26
gcd(2, 3) = 1
gcd(2, 10) = 2
gcd(25, 35) = 5
gcd(14, 28) = 14
Approach 1: Brute-force, start from min(n, m) down to 1, to check if a number is common divisor for both m and n, if so, it is the greatest common divisor.
Approach 2: Euclid’s algorithm
Approach 3: Recursive method
GCD
is the largest positive integer that divides
The numbers without a remainder
Approach 2: Euclid’s algorithm
27
// Get absolute value of m and n;
t1 = Math.abs(m);
t2 = Math.abs(n);
// r is the remainder of t1 divided by t2;
r = t1 % t2;
while (r != 0) {
t1 = t2;
t2 = r;
r = t1 % t2;
}
// When r is 0, t2 is the greatest common
// divisor between t1 and t2
return t2;
Approach 3: Recursive Method
28
gcd(m, n) = n if ( m % n = 0 );
gcd(m, n) = gcd(n, m % n); otherwise;
private static int gcd(int m, int n) { if (m % n == 0) return n; else return gcd(n, m % n); }
29
Knapsack Problem
Load a knapsack with any number of items without exceeding its capacity.
//knapsack problem. Simple case - no optimization
ArrayList<Integer> items = new ArrayList<Integer> (
Arrays.asList(8, 2, 9, 4, 1, 5, 3, 4, 2, 6, 7));
ArrayList<Integer> solution = new ArrayList<Integer>();
knapsack(16, solution, items);
for (int n : solution){
System.out.println("Knapsack: " + n );
}
Picture taken from: http://en.wikipedia.org/wiki/Knapsack_problem
30
Knapsack Problem
Load a knapsack with any number of items without exceeding its capacity. private static void knapsack(int maxWeight, ArrayList<Integer> solution, ArrayList<Integer> items) { if ((maxWeight >= 0 ) && (items.size()>0) ) { int item = items.remove(0); solution.add(0, item); knapsack(maxWeight-item, solution, items); } else { int item = solution.remove(0); if (items.size()==0) return; else{ knapsack(maxWeight+item, solution, items); } } }
Picture taken from: http://en.wikipedia.org/wiki/Knapsack_problem
Fractals?
31
A fractal is a geometrical figure
just like triangles, circles, and
rectangles, but fractals can be
divided into parts, each of which is
a reduced-size copy of the whole.
Sierpiński Triangle
32
1. It begins with an equilateral triangle, which is considered to be the Sierpinski fractal of order (or level) 0, as shown in Figure (a).
2. Connect the midpoints of the sides of the triangle of order 0 to create a Sierpinski triangle of order 1, as shown in Figure (b).
3. Leave the center triangle intact. Connect the midpoints of the sides of the three other triangles to create a Sierpinski of order 2, as shown in Figure (c).
4. You can repeat the same process recursively to create a Sierpinski triangle of order 3, 4, ..., and so on, as shown in Figure (d).
Sierpinski Triangle Solution
33
p1
p3 p2
midBetweenP1P2 midBetweenP3P1
midBetweenP2P3
Sierpinski Triangle Solution
34
public void drawTriangle (int order, Point p1, ponit p2, Point p3) if (order == 0) return; else { // calculate midpoints of triangle p1-p2-p3 p12 = midPoint (p1, p2); p13 = midPoint(p1, p3); p23 = midPoint(p2, p3); // draw inner Sierpinski triangles of smaller order drawTriangle(order-1, p1, p12, p13); drawTriangle(order-1, p12, p2, p23); drawTriangle(order-1, p13, p23, p3); } }
Eight Queens
35
0
4
7
5
2
6
1
3
queens[0]
queens[1]
queens[2]
queens[3]
queens[4]
queens[5]
queens[6]
queens[7]
Eight Queens
36
0 1 2 3 4 5 6 7
0
1
2
3
4
5
6
7
upright diagonal
upleft
check
colum
n
Eight Queens
37
// start by calling: search(0); // search for a solution starting on specified row private static boolean search(int row){ if (row == SIZE) return true; for (int column=0; column < SIZE; column++){ queens[row] = column; //place a queen at row,column if (isValid(row, column) && search(row+1)){ System.out.println("Queen at: " + row + " : " + column); return true; } } return false; }//search // check if a queen can be placed at row i and column j private static boolean isValid(int row, int column){ for(int i=1; i<= row; i++){ if ( queens[row-i] == column //check column || queens[row-i] == column - i //check upleft diagonal || queens[row-i] == column + i )//check upright diagonal return false; } return true; }//isValid