Module 7: Supplemental Material


Ternary Search

Why ternary search?

First, let's examine an implementation:
public class TernarySearch {

    static boolean ternarySearch (int[] A, int value, int start, int end)
    {
        if (start > end) {
            return false;
        }

        // First boundary: add 1/3 of length to start.
	int mid1 = start + (end-start) / 3;
        
        // Second boundary: add 2/3 of length to start.
	int mid2 = start + 2*(end-start) / 3;

	if (A[mid1] == value) {
	    return true;
	}
	else if (A[mid2] == value) {
	    return true;
	}
	else if (value < A[mid1]) {
	    // Search 1st third.
	    return ternarySearch (A, value, start, mid1-1);
	}
	else if (value > A[mid2]) {
	    // Search 3rd third.
	    return ternarySearch (A, value, mid2+1, end);
	}
	else {
	    // Middle third.
	    return ternarySearch (A, value, mid1,mid2);
	}
    }

}
Note:

Exercise 1: Binary search takes O(log2(n)) time. We might guess that ternary search takes O(log3(n)) time. Prove this by taking some large number n and repeatedly dividing by 3 until you can't divide anymore (i.e., the remainder is less than 3). Next, use the fact that loga(n) = logb(n) / logb(a) to evaluate log3(n) exactly and compare.

Exercise 2: So, is ternary search faster? Download TernarySearch.java and compare with Binary Search. All you have to do is compile and execute.

Exercise 3: Does it make sense to take this idea further to quartenary search? Give an argument for why it does not make sense.

Mixing binary and ternary search:

Here's how:
public class MixedSearch {

    static int CUT_OFF = 10;

    static boolean mixedSearch (int[] A, int value, int start, int end)
    {
        if (start > end) {
            return false;
        }

        // Switch to binary search if range is smaller than CUT_OFF.
        if (start-end < CUT_OFF) {
            return binarySearch (A, value, start, end);
        }
        
        // Otherwise, stay with ternary search.

        // First boundary: add 1/3 of length to start.
	int mid1 = start + (end-start) / 3;
        
        // Second boundary: add 2/3 of length to start.
	int mid2 = start + 2*(end-start) / 3;

	if (A[mid1] == value) {
	    return true;
	}
	else if (A[mid2] == value) {
	    return true;
	}
	else if (value < A[mid1]) {
	    // Search 1st third.
	    return ternarySearch (A, value, start, mid1-1);
	}
	else if (value > A[mid2]) {
	    // Search 3rd third.
	    return ternarySearch (A, value, mid2+1, end);
	}
	else {
	    // Middle third.
	    return ternarySearch (A, value, mid1,mid2);
	}
    }

}

Exercise 4: Download MixedSearch.java, compile and execute to compare all three: binary, ternary and mixed search. Experiment with different cut-off values to see what works best for MixedSearch.


Array list revisited

Deletion in an array list:

Here's the program:
public class OurArrayList2 {

    // This is the array in which we'll store the integers.
    Integer[] data = new Integer [1];

    // Initially, there are none.
    int numItems = 0;


    public void add (Integer K)
    {
        // ...
    }


    public Integer get (int i)
    {
        // ...
    }


    public boolean contains (Integer K)
    {
        // ...
    }


    public void delete (Integer K)
    {
	// First, find it.
	for (int i=0; i < numItems; i++) {
	    if (data[i] == K) {
		// Delete it and shift left all the items that come later.
		for (int j=i; j < numItems-1; j++) {
		    data[j] = data[j+1];
		}
		numItems --;
		break;
	    }
	}

        // Check if size needs to be reduced.
	if (numItems < data.length/2) {
	    // Reduce size.
            reduce ();
	}
    }


    void reduce ()
    {
        Integer[] data2 = new Integer [data.length/2];
        for (int i=0; i < numItems; i++) {
            data2[i] = data[i];
        }
        data = data2;
    }
    

    public void deleteLast ()
    {
        // All we need to do is change the current size.
        numItems --;
        
        // Check if size needs to be reduced.
	if (numItems < data.length/2) {
	    // Reduce size.
            reduce ();
	}
    }

}
Note:

Exercise 5: Consider an existing array list with n elements. Suppose we repeatedly call deleteLast() n times. Argue that the time taken is proportional to n/2 + n/4 + n/8 + ... + 1. Write a small program to compute n/2 + n/4 + n/8 + ... + 1 for various values of n. Can you simplify the sum and show that n/2 + n/4 + n/8 + ... + 1 = (1 - 1/n)?


© 2006-2020, Rahul Simha & James Taylor (revised 2020)