
public class SearchingTest {

	public static final int ARRAY_LENGTH = 1000000;
	public static final int MAX_SPACING = 10;
	public static final int MAX_VALUE = MAX_SPACING*ARRAY_LENGTH;
	public static final int TRIALS = 100000;
	
	
	public static void main(String[] args) {
		//create our data set
		int[] data = createRandomSortedArray(ARRAY_LENGTH, MAX_SPACING);

		System.out.println(data[data.length - 1]);
		//find things linearly
		testLinear(data);
		
		//find things binary
		testBinary(data);
	} //end main
	
	
	/**
	 * testLinear
	 * Calculate the amount of time it takes to perform linear searches of random values, and output the result. 
	 * @param data an array of integers to test
	 */
	public static void testLinear(int[] data) {

		int found = 0;
		long t1 = System.currentTimeMillis();
		for(int i = 0; i < TRIALS; i++) {
			int value = (int)(Math.random()*MAX_VALUE);
			if(linearSearch(data, value) >= 0) {
				found++;
			} //end if
		} //end for
		long t2 = System.currentTimeMillis();
		outputResult("Linear", t2-t1, found);
	} //end testLinear
	
	/**
	 * testBinary
	 * Calculate the amount of time it takes to perform binary searches of random values, and output the result. 
	 * @param data an array of integers to test
	 */
	public static void testBinary(int[] data) {

		int found = 0;
		long t1 = System.currentTimeMillis();
		for(int i = 0; i < TRIALS; i++) {
			int value = (int)(Math.random()*MAX_VALUE);
			if(binarySearch(data, value) >= 0) {
				found++;
			} //end if
		} //end for
		long t2 = System.currentTimeMillis();
		outputResult("Binary", t2-t1, found);
	} //end testBinary
	
	
	/**
	 * outputResult
	 * Output the summary of the trials
	 * @param name The name of the search.
	 * @param time The number of milliseconds taken to run the trials
	 * @param found The number of successful completions
	 */
	public static void outputResult(String name, long time, int found) {
		System.out.printf("%s search took %d milliseconds. Found %d out of %d. (%.4f%%)\n", 
				name, time, found, TRIALS, (100.0*found)/TRIALS);
		
	} //end outputResult
	
	/**
	 * createRandomArray
	 * Create an array of random ints, r, such that 0 <= r < max.
	 * @param length the length of the resulting array.
	 * @param max the exclusive upper bound for the random numbers. 
	 * @return a new array of length ints between 0 and max (excluding max).
	 */
	public static int[] createRandomArray(int length, int max) {
		int[] result = new int[length];
		
		for(int i = 0; i < result.length; i++) {
			result[i] = (int)(Math.random()*max);
		} //end for
		
		return result;
	} //end createRandomArray
	
	
	/**
	 * Create a random array of values in ascending order. Each element will be a random distance 
	 * between 1 and spacing from the previous value.
	 * @param length the length of the resulting array.
	 * @param spacing the max absolute value between two adjacent element.
	 * @return a new array of length ints in ascending order.
	 */
	public static int[] createRandomSortedArray(int length, int spacing){
		int[] result = new int[length];

		int current = 0;
		for(int i = 0; i < result.length; i++){
			//add a random number between 1 and 10 to the current value
			current = current + (int)(Math.random()*spacing) + 1;
			result[i] = current;
		} //end for
		
		return result;
	} //end createRandomSortedArray
	
	/**
	 * linearSearch
	 * Search the array, data, for the value n, one item at a time from element 0.
	 * @param data An array of ints to search.
	 * @param n The value to find in the array
	 * @return  the index where n appears if it is in the array, otherwise -1.
	 */
	public static int linearSearch(int[] data, int n){
		for(int i = 0; i < data.length; i++){
			if(data[i] == n){
				return i;
			} //end if
		} // end for
		return -1;
	} // end linear search
	
	/**
	 * findValueBinary
	 * Perform a binary search to find n in the array data.
	 * @param data An array of integers sorted from lowest to highest.
	 * @param n The value to find in the array
	 * @return the index of the item, n, in the array or -1 if n was not found
	 */
	public static int binarySearch(int[] data, int n){
		int low = 0;
		int high = data.length - 1;
		
		//keep going until we determine the value is not there
		while(low <= high) {
			int mid = (low + high)/2;
			
			if(n < data[mid]) {
				//low stays the same
				high = mid - 1;
			}
			else if(n > data[mid]) {
				//high stays the same
				low = mid + 1;
			}
			else {
				//n == data[mid]
				//found it!
				return mid;
			}
		}
		
		//not found
		return -1;
	} //end binarySearch

}
