JAVA Assignment
INFSCI 2500 Lecture 3 Analysis of Algorithms and Recursion
Today’s Goals
Review Homework 1
Understand Big-O notation
Conduct runtime analyses
Understand Recursion
Recognize where recursion is useful
Compare recursive and iterative solutions
Trace the execution of a recursive method
Assign Homework 2
Homework 1 Review
Effectiveness vs Efficiency
What is the method supposed to do?
How does the method do that?
How do we measure efficiency?
Time it?
Investigate directly?
Outside of a computing environment?
Running Time
Number of statements executed proportional to run time
Size of problem: n
worstTime(n)
Maximum number of statements executed
averageTime(n)
Average number of statements executed
bestTime(n)
Minimum number of statements executed
Worst Time Example
public static int aboveMeanCount(double[] a, double mean){
int count=0;
for(int i=0;i<a.length;i++){
if(a[i]>mean){
count++;
}
}
return count;
}
What is the problem size?
What is the worstTime(n)?
Worst Time Example
public static int aboveMeanCount(double[] a, //1,1 double mean){
int count=0; //1
for(int i=0;i<a.length;i++){ //1,n+1,n
if(a[i]>mean){ //n
count++; //n-1
}
}
return count; //1
}
worstTime(n)=5+(n+1)+n+n+(n-1)=4n+5
Average Time Example
public static int aboveMeanCount(double[] a, //1,1 double mean){
int count=0; //1
for(int i=0;i<a.length;i++){ //1,n+1,n
if(a[i]>mean){ //n
count++; //n/2
}
}
return count; //1
}
averageTime(n)=5+(n+1)+n/2+n+(n-1)=3.5n+5
Best Time Example
public static int aboveMeanCount(double[] a, //1,1 double mean){
int count=0; //1
for(int i=0;i<a.length;i++){ //1,n+1,n
if(a[i]>mean){ //n
count++; //1
}
}
return count; //1
}
bestTime(n)=6+(n+1)+n+(n-1)=3n+6
Big-O Notation
worstTime,averageTime are crude approximations
We are removed from a computing environment
We can use an approximate approximation
We only care about an upper bound!
“How bad can it get?”
Big-O Definition
Let g be a function that has nonnegative integer arguments and returns a nonnegative value for all arguments. A function f is said to be O(g) if for some pair of nonnegative constants C and K:
f(n)<=Cg(n) for all n>=K
Got it???
Big-O Simplified
We care about the “order” of the worstTime(n) value
worstTime(n) = 4n+5 = O(n)
“The method is big-oh of n”
“Time complexity of n”
Big-O Example
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
System.out.println(i+j);
}
}
Big-O Example
for(int i=0;i<n;i++){ //1,n+1,n
for(int j=0;j<n;j++){ //n(1,n+1,n)
System.out.println(i+j); n(n)
}
}
worstTime(n)=1+(n+1)+n+n(1+(n+1)+n)=
2n2+4n+2
Big-O Example
for(int i=0;i<n;i++){ //1,n+1,n
for(int j=0;j<n;j++){ //n(1,n+1,n)
System.out.println(i+j); n(n)
}
}
worstTime(n)=1+(n+1)+n+n(1+(n+1)+n)=
3n2+4n+2
=O(n2)
Common Big-O Values
O(1)
O(log n)
O(n)
O(n log n)
O(n2)
O(n3) & so on
O(2n)
Growth Rate
Finding Big-O Quickly
Estimate the number of loop iterations
How it that related to n?
Big-O Example 1
double sum=0;
for(int i=0;i<100000000;i++){
sum+=Math.sqrt(i);
}
Big-O Example 1
double sum=0; //1
for(int i=0;i<1000000000;i++){ //1, 1 billion+1,
1billion
sum+=Math.sqrt(i); //1 billion
}
worstTime(n)=1+1+1+3 billion
Just a constant
=O(1) “constant time”
Big-O Example 2
while(n>1){
n/=2;
}
Big-O Example 2
while(n>1){
n/=2; //log n
}
O(log n) “logarithmic time”
Splitting rule:
In general, if n (the problem size) is split up in some way within a loop, it will be O(log n)
Big-O Example 3
for(int i=0;i<n;i++){
System.out.println(i);
}
Big-O Example 3
for(int i=0;i<n;i++){ //1,n+1,n
System.out.println(i); //n
}
=O(n) “linear time”
Big-O Example 4
int m;
for(int i=0;i<n;i++){
m=n;
while(m>1){
m/=2;
}
}
Big-O Example 4
int m; //1
for(int i=0;i<n;i++){
m=n; //n
while(m>1){
m/=2; //log n
}
}
=O(n log n) “linear-logarithmic time”
Big-O Example 5
for(int i=0;i<n;i++){
System.out.println(i);
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
System.out.println(i);
}
}
Big-O Example 5
for(int i=0;i<n;i++){
System.out.println(i); //n
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
System.out.println(i); //n*n
}
}
=O(n2 +n)…? No!
=O(n2) “quadratic time”
Big-O Example 6
int k=1;
for(int i=0;i<n;i++){
k*=2;
}
for(int i=0;i<k;k++){
System.out.println(i);
}
Big-O Example 6
int k=1; //1
for(int i=0;i<n;i++){
k*=2; //n
}
for(int i=0;i<k;k++){
System.out.println(i); //k
}
After first loop, k=2n
Therefore O(2n) “exponential time”
Other Big-O Values
O(n!) – “factorial time”
Traveling Salesman Problem
O(∞) – “infinite time”
Flipping a coin until it lands on heads
It might never happen!
Growth Rate
Runtime Analysis
Elapsed time is an inaccurate measure of runtime efficiency
Using different sizes of N and examining the relative differences gives a better approximation
HW1
Recursion
Recursive methods call themselves
How to avoid an infinite loop?
if(simplest case){
solve directly
}
else{
call again with a simpler case
}
When To Use Recursion
Complex cases can be reduces to simpler cases
Simple cases can be solved directly
Recursion Example - Factorials
Given int n, find n!
4!=4*3*2*1=24
How can this be simplified?
Recursion Example - Factorials
Given int n, find n!
4!=4*3*2*1=24
How can this be simplified?
4!=4*3!
Remember, 0!=1
Recursion Example - Factorials
public static long factorial(int n){
if(n<0){
throw new IllegalArgumentExemption();
}
if(n<=1){
return 1;
}
return n*factorial(n-1);
}
Execution Frames
Use to trace a recursive method
39
Time Analysis of factorial()
public static long factorial(int n){
if(n<0){
throw new IllegalArgumentExemption();
}
if(n<=1){
return 1;
}
return n*factorial(n-1);
}
Time Analysis of factorial()
public static long factorial(int n){
if(n<0){
throw new IllegalArgumentExemption(); //1
}
if(n<=1){
return 1; //1
}
return n*factorial(n-1); //n-1
}
=O(n)
Iterative v Recursive
All recursive problems can be solved iteratively
Often there is a tradeoff
Time
Space
Iterative Factorial
public static long factorial(int n){
int product=n;
if(n<0){
throw new IllegalArgumentException;
}
if(n==0){
return 1;
}
for(int i=n-1;i>1;i--){
product*=i;
}
return product;
}
Iterative Factorial
public static long factorial(int n){
int product=n;
if(n<0){
throw new IllegalArgumentException; //1
}
if(n==0){
return 1; //1
}
for(int i=n-1;i>1;i--){
product*=i; //n-1
}
return product; //1
}
=O(n)
Space?
Decimal to Binary
Convert base 10 to base 2
n=25? 11001 1*24 + 1*23 + 0*22 + 0*21 + 1*20
In binary, least significant bit = n%2
Remaining bits =n/2
Decimal to Binary
n=12
12/2=6 ; 12%2=0
6/2=3; 6%2=0
3/2=1; 3%2=1
When the n/2 quotient is 1, result is 1.
Then read from the bottom up
12=1100
Decimal to Binary
n/2 needs to be calculated before we append n%2
n%2 is appended to result of recursive call
getBinary
public static String getBinary(int n){
if(n<0){
throw new IllegalArgumentException();
}
if(n<=1) {
return Integer.toString(n);
}
return getBinary(n/2)+Integer.toString(n%2);
}
getBinary
public static String getBinary(int n){
if(n<0){
throw new IllegalArgumentException();
} //1
if(n<=1) {
return Integer.toString(n); //1
}
return getBinary(n/2)+Integer.toString(n%2);
} //floor(log2n) --splitting rule
=O(log n)
getBinaryIterative
public static String getBinaryIterative(int n){
if(n<0){
throw new IllegalArgumentException();
}
String result="";
int remainder = 0;
while(decimalNumber >= 0) {
remainder = decimalNumber % 2;
decimalNumber /= 2;
result=remainder+result;
}
return(result);
}
Towers of Hanoi
One disk may move at a time
No big disk ever on top of a smaller disk
Top disk may be moved to any pole
A B C
1
2
3
4
Towers of Hanoi
A B C
Towers of Hanoi
For n disks:
Move n-1 disks from A to C, with B as temporary
Move disk n from A to B
Move n-1 disks from C to B, with A as temporary
A = origin
B = destination
C = temporary
Towers of Hanoi
For n disks:
Move n-1 disks from origin to temporary
Move disk n from origin to destination
Move n-1 disks from temporary to destination
A = origin
B = destination
C = temporary
Towers of Hanoi
public static String move(int n, char orig, char dest, char temp){
final String DIRECT_MOVE=“Move disk “+ n +” from “ + orig + “ to “ + dest + “\n”;
if(n==1) return DIRECT_MOVE;
String result=move(n-1,orig,temp,dest);
result+=DIRECT_MOVE;
result+= move(n-1,temp,dest,orig);
return result;
}
Towers of Hanoi Time Analysis
worstTime(n) for a recursive function is directly proportional to the number of recursive calls
Number of steps to complete any game = 2n -1
worstTime(n) is exponential!
O(2n)
Intractable problem
Towers of Hanoi
Array Searching
Searching an array is easy
Start at the beginning, look at every element until you find a match
Return that index
What if the target is at the end?
worstTime(n) is linear, O(n)
Can we do better?
Binary Search
Divide-and-conquer
Assume sorted collection
Input:
the collection
smallest index (0)
largest index
key (target)
Binary Search
Find midpoint of collection
Compare that to key
If greater, search the first half
If lesser, search the last half
If equal, you are done!
Return the index where the key was found
Comparable Interface
public interface Comparable{
//Return less than zero if this is less than obj
//Return greater than zero if this is greater than obj
//Return zero if this is equal to obj
public int compareTo(Object obj)
}
String s = “hello”;
s.compareTo(“world”); //return less than zero
Integer i = 4;
i.compareTo(3); //return greater than zero
Build Binary Search
Conclusion
Recursion is a method calling itself
Iterative solutions are preferable to recursive solutions
If the problem complexity can be reduced to simpler cases in the same form
Simplest case can be solved directly
Any recursive method can be made iterative
Its not always better!
Homework 2