import SimpleOutput; /** * Trinary search. A strange variant of binary search. Intended * as an example for the answer key for HW6 of CS152 99S. * * @author Samuel A. Rebelsky * @version 1.0 of March 1999 */ public class TrinarySearch { // +---------+------------------------------------------------- // | Methods | // +---------+ /** * Determine the index of x in array A. * Pre: A is sorted in increasing order. * Post: If x is in A, then returns i s.t. A[i] == x * Post: If x is not in A, then throws an exception */ public int trinarySearch(int x, int[] A) throws Exception { // Use the marvelous helper function return trinarySearch(x, A, 0, A.length-1); } // trinarySearch(int, int[]) /** * Determine the index of x in the subarray of A given by lb..ub. * Pre: A is sorted in increasing order. * Pre: If x is in A, then x is in the subarray. * Pre: If x is not in A, then x is not in the subarray. * Post: If x is in A, then returns i s.t. A[i] == x * Post: If x is not in A, then throws an exception */ public int trinarySearch(int x, int[] A, int lb, int ub) throws Exception { // Base case: empty subarray. x is not in A. if (ub < lb) throw new Exception("Not found"); // Base case: single-element subarray. See if x is that element. else if (lb == ub) { if (x == A[lb]) return lb; else throw new Exception("Not found"); } // single-element subarray // Recursive cases: split the array and search the appropriate subarray. else { // The first split point is one-third of the way from lb to ub. We // compute the distance from lb to ub, take 1/3 of that, and add it // to lb. int splitOne = lb + (ub-lb)/3; // The second split point is two-thirds of the way from lb to ub. We // compute the distance from lb to ub, take 2/3 of that, and add it // to lb. int splitTwo = lb + (2 * (ub-lb))/3; // Recursive case: in the first third of the array. if (x <= A[splitOne]) return trinarySearch(x, A, lb, splitOne); // Recursive case: in the second third of the array. else if (x <= A[splitTwo]) return trinarySearch(x, A, splitOne+1, splitTwo); // Recursive case: in the third third of the array. else return trinarySearch(x, A, splitTwo+1, ub); } } // trinarySearch(int, int[], int, int) // +------+---------------------------------------------------- // | Main | // +------+ /** * Test the search method. Technique: build a number of sorted * arrays of different lengths (note that content should not * affect our search method, so we can use any sorted content * we choose) and consider every position in each array, as * well as every "between" position in each array. To make it * easier to do this, we make arrays of the form {2,4,6,8,...2*n} * and search for values from 1 to 2*n+1. */ public static void main(String[] args) { // Create something that can search. TrinarySearch searcher = new TrinarySearch(); // The array we'll be using int[] values; // The position found. int pos; // For output. SimpleOutput out = new SimpleOutput(); // For each reasonable size of array for (int size = 1; size <= 10; ++size) { // A note. out.println("Checking array of size " + size); // Build the array. values = new int[size]; // Fill in the elements of the array with the numbers // from 2 to 2*size. for (int i = 1; i <= size; ++i) { values[i-1] = 2*i; } // Search for values between 1 and 2*size + 1. for (int val = 1; val <= 2*size+1; ++val) { try { pos = searcher.trinarySearch(val,values); // If it's odd, it shouldn't have a position. if (val % 2 == 1) out.println(" ERROR! The position of " + val + " was given as " + pos); // If it's even, it's position should be (val/2)-1. else if (pos != (val/2)-1) { out.println(" ERROR! The position of " + val + " was given as " + pos); } } catch (Exception e) { // It's okay to throw exceptions for odd numbers // (which aren't in the array). But even numbers // should be there. if (val % 2 == 0) out.println(" ERROR! Indicated that " + val + " was not in the array"); } // catch } // for each value } // for each size } // main } // TrinarySearch