135 Week 11
135 Week 11
Week 11
By
Javed Siddique
Objectives
After this week, you should be able to
Write recursive algorithms.
Decide when to use recursion.
Perform linear and binary search algorithms on
small arrays.
Determine whether a linear or binary search is
more effective for a given situation.
Understand selection, bubble sort, and
(recursive) quicksort algorithms.
Understand how these algorithms compare.
Recursive Algorithms
Within a given method, we are allowed to
call other accessible methods.
It is also possible to call the same method
from within the method itself.
This is called a recursive call.
For certain problems a recursive solution is
very natural and simple.
It is possible to implement a recursive
algorithm without using recursion, but the
code can be more complex.
Example of Recursion
The factorial of N is the product of the first N
positive integers:
N! = N * (N – 1) * (N – 2 ) * . . . * 2 *1
This is useful for many situations, e.g.
there are n! possible sequences of n objects
there are n!(n-k)!/k! unique subsets of size k, from a
set of size n.
The factorial of N can be defined recursively as
1 if N = 1
factorial( N ) =
N * factorial( N-1 ) otherwise
Recursive Method
An recursive method is a method that contains a
statement (or statements) that makes a call to itself.
Implementing the factorial of N recursively will result in the
following method.
} else {
Recursive case directoryListing( file ); //it's a directory
} //so make a
} //recursive call
}
Anagram
List all anagrams of a given word.
Word CAT
CTA
ATC
Anagrams
ACT
TCA
TAC
Anagram Solution
The basic idea is to make recursive calls on a
sub-word after every rotation. Here’s how:
C A T Recursion
CAT
CTA
Rotate Left
A T C Recursion
ATC
ACT
Rotate Left
TCA
T C A Recursion
TAC
Anagram Method
public void anagram( String prefix, String suffix ) {
String newPrefix, newSuffix;
int numOfChars = suffix.length();
Test if (numOfChars == 1) {
//End case: print out one anagram
End case System.out.println( prefix + suffix );
} else {
for (int i = 1; i <= numOfChars; i++ ) {
newSuffix = suffix.substring(1, numOfChars);
newPrefix = prefix + suffix.charAt(0);
Recursive case anagram( newPrefix, newSuffix );
//recursive call
//rotate left to create a rearranged suffix
suffix = newSuffix + suffix.charAt(0);
}
}
}
Towers of Hanoi
The goal of the Towers of Hanoi puzzle is to
move N disks from Peg 1 to Peg 3:
– Only one disk can
Start: be moved at a
time.
– A larger disk
Peg1 Peg2 Peg3
cannot be placed
on top of a
smaller disk.
Goal:
Test if ( N == 1 ) {
} else {
towersOfHanoi( N-1, from, spare, to );
Recursive case moveOne( from, to );
towersOfHanoi( N-1, spare, to, from );
}
}
number
0 1 2 3 4 5 6 7 8
23 17 5 90 12 44 38 84 77
Linear Search
Search the array from the first to the last
position in linear progression.
public int linearSearch ( int[] number, int searchValue ) {
int loc = 0;
while (loc < number.length && number[loc] != searchValue) {
loc++;
}
if (loc == number.length) { //Not found
return NOT_FOUND;
} else {
return loc; //Found, return the position
}
}
Linear Search Performance
We analyze the successful and
unsuccessful searches separately.
We count how many times the search value
is compared against the array elements.
Successful Search
Best Case – 1 comparison
Worst Case – N comparisons (N – array size)
Unsuccessful Search
Best Case =
Worst Case – N comparisons
Binary Search
number
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
0 1 2 3 4 5 6 7 8
5 12 17 23 38 44 77 84 90
int low = 0,
high = number.length - 1,
mid = (low + high) / 2;
while (low <= high && number[mid] != searchValue) {
if (number[mid] < searchValue) {
low = mid + 1;
} else { //number[mid] > searchValue
high = mid - 1;
}
mid = (low + high) / 2; //integer division will truncate
}
if (low > high) {
mid = NOT_FOUND;
}
return mid;
}
Binary Search Performance
Successful Search
Best Case – 1 comparison
Worst Case – log2N comparisons
Unsuccessful Search
Best Case =
Worst Case – log2N comparisons
Since the portion of an array to search is cut into
half after every comparison, we compute how
many times the array can be divided into halves.
After K comparisons, there will be N/2K elements in
the list. We solve for K when N/2K = 1, deriving K =
log2N.
Comparing N and log2N Performance
1 5 17 23 90 12 44 38 84 77
Result AFTER one
pass is completed.
sorted
2 5 12 23 90 17 44 38 84 77
3 5 12 17 90 23 44 38 84 77
7 5 12 17 23 38 44 77 84 90
8 5 12 17 23 38 44 77 84 90
Selection Sort Routine
public void selectionSort( int[] number )
{
int startIndex, minIndex, length, temp;
length = number.length;
exchange exchange
17 23 5 90 12 44 38 84 77 17 5 23 12 44 38 90 84 77
exchange exchange
17 5 23 90 12 44 38 84 77
17 5 23 12 44 38 84 90 77
exchange
ok exchange
17 5 23 12 90 44 38 84 77 17 5 23 12 44 38 84 77 90
exchange
The largest value 90 is at the end of
the list.
Bubble Sort Routine
public void bubbleSort(int[] number) {
bottom = number.length - 2;
while (exchanged) {
exchanged = false;
low high
p ...
if (N == 0 || N == 1) {
return 1;
} else {
return fibonacci(N-1) + fibonacci(N-2);
}
}
Excessive Repetition
Recursive Fibonacci ends up repeating the
same computation numerous times.
fibonacci(5)
fibonacci(4)+fibonacci(3)
fibonacci(2)+fibonacci(1)
fibonacci(1)+fibonacci(0)
fibonacci(3)+fibonacci(2)
fibonacci(1)+fibonacci(0)
fibonacci(2)+fibonacci(1)
fibonacci(1)+fibonacci(0)
Non-recursive Fibonacci
public int fibonacci( int N ) {
if (N == 0 || N == 1 ) {
return 1;
} else {
fibN1 = fibN2 = 1;
cnt = 2;
while ( cnt <= N ) {
fibN = fibN1 + fibN2; //get the next fib no.
fibN1 = fibN2;
fibN2 = fibN;
cnt ++;
}
return fibN;
}
}
When Not to Use Recursion