course-web-page-fall-2022

Course web page for Data Structures H343 Fall 2022

View the Project on GitHub IUDataStructuresCourse/course-web-page-fall-2022

Lecture: Code Review & Algorithm Analysis

Code Review of the Search Lab

Part 1: find_first_true

Student solutions.

Solution #1

public static int find_first_true(boolean[] A, int begin, int end){
	for (int i = begin; i != end; i++) {
		if (A[i]) {
			return i;
		}
	}
    return end;
}

Notes:

Solution #2

public static int find_first_true(boolean[] A, int begin) {
	if(A.length == begin || A[begin]) {
		return 0;
	}
	return 1 + find_first_true(A, begin + 1);
}
public static int find_first_true(boolean[] A, int begin, int end) {
	return begin + find_first_true(Arrays.copyOf(A, end), begin);		
}

Notes:

Solution #3

public static int find_first_true(boolean[] A, int begin, int end) {
    for (int i = begin; i != end; i++) {
        if (A[i]) {
            return i;
        }
    }
    return end;
}

Notes:

Part 2: find_first_equal

Student solutions.

Solution #1

public static int find_first_equal(int[] A, int x) {
    for (int i = 0; i < A.length; i++) {
        if(A[i] == x){
            return i;
        }
    }
    return A.length;
}

Solution #2

public static int find_first_equal(int[] A, int x) {
    boolean[] newArr = new boolean[A.length];
    for (int i = 0; i < A.length; i++) {
        newArr[i] = (A[i] == x);
    }
    return find_first_true(newArr, 0, A.length);
}

Solution #3

public static int find_first_equal(int[] A, int x) {
    boolean[] B = new boolean[A.length];
    for(int i=0;i!=A.length;i++) {
        B[i]=(x==A[i]);
    }
    return find_first_true(B,0, B.length);
}

Part 3: first_first_true_sorted

Student solutions.

Solution #1

public static int find_first_true_sorted(boolean[] A, int begin, int end) {
    if (end > 1) {
        int middle = (int)end/2;
        if (A[middle] == true){
            while(A[middle] != false){
                middle--;
            }
            return middle+1;
        }
        else{
            while(A[middle] == false){
                middle++;
            }
        }
        return middle;
    }
    else if (end == 1) 
	    return 0;
    else {
        return end;
	}
}

Solution #2

public static int find_first_true_sorted(boolean[] A, int begin, int end) {
    int middle = end - begin;
    if (begin == 0) {
        middle /= 2;
    }
    if(middle < end && middle > begin) {
        if(A[middle]) {
            end = middle;
            return (find_first_true_sorted(A, begin, end));
        } else {
            begin = middle;
            return (find_first_true_sorted(A, begin, end));
        }
    } else {
        if (end == 1 && begin == 0) {
            if(!A[0]) {
                return end;
            } else {
                return begin;
            }
        } else {
            return end;
        }
    }
}

Solution #3

public static int find_first_true_sorted(boolean[] A, int begin, int end) {
    if (A.length == 0) 
	    return 0;
    int mid;
    while(end - begin > 1) {
        mid = (begin + end)/2;
        if(A[mid]) {
            end = mid;
        } else {
            begin = mid + 1;
        }
    }
    if (A[begin]) 
	    return begin;
    else
	    return end;
}

Solution #4

public static int find_first_true_sorted(boolean[] A, int begin, int end) {
	if(end - begin == 0) {
		return end;
	} else {
		int middle = (end-begin)/2 + begin;
		if(A[middle]) {
			return find_first_true_sorted(A, begin, middle);
		} else {
			return find_first_true_sorted(A, middle+1, end);
		}
	}
}

Time Complexity

We are interested in the running time as the inputs grow large.

We care about the growth rate of an algorithm’s run-time more than it’s value at a particular point.

We focus on the worst-case run-time of algorithms because we want to offer guarantees to the user of an algorithm

Our goal is to classify functions that grow at a similar rate, ignoring details that don’t matter.

Functions to think about: n, 10n, lg n, n lg n, 10 n², n² + n

Asymptotic Upper Bound

Definition (Big-O) For a given function g, we define O(g) as the the set of functions that grow similarly or slower than g. More precisely, f ∈ O(g) iff ∃ k c. ∀ n ≥ k. f(n) ≤ c g(n).

We say that g(n) is an asymptotic upper bound of all the functions in the set O(g).

Notation We write f ≲ g iff f ∈ O(g), and say that f is asymptotically less-or-equal to g.

Demonstrate the main idea and the role of k and c.

https://www.desmos.com/calculator

e.g. 4x versus x²

  1. Is 4x ≲ x²?
  2. Is x² ≲ 4x?

e.g. x + 10 versus x

  1. Is x + 10 ≲ x?
  2. Is x ≲ x + 10?

Example Let’s show that (n² + n + 10) ∈ O(n²). So we need to find a constant c such that

n² + n + 10 ≤ c n² when n is large.

We divide both sides by n².

1 + 1/n + 10/n² ≤ c

When n is large, the terms 1/n and 10/n² get very small, so we need to choose something a bit bigger than 1, so we choose c = 2.

Next we need to find a constant k such that

n² + n + 10 ≤ 2 n² when n is greater than k.

We compute a handful of values of these functions.

n n² + n + 10 2n²
1 12 2
2 16 8
3 22 18
4 30 32
5 40 50
6 52 72

We see that from n=4 and onwards, 2n² is greater than n² + n + 10, so we choose k = 4. We have some emprical evidence that we’ve made the correct choices, but to know for sure, we prove the following theorem.

Theorem ∀ n ≥ 4, n² + n + 10 ≤ 2 n².

Proof. We proceed by induction on n.

Student exercise

Show that 2 log n ∈ O(n / 2).

Hint: experiment with values of n that are powers of 2 because it is easy to take the log of them:

log(2) = 1
log(4) = 2
log(8) = 3
...

Reasoning about asymptotic upper bounds