/*********************************************
 * Binary Search Author:
 *
 * Description:
 * First, a quick review of linear search with a recursive implementation.
 * 
 * Use recursive binary search to find the position of an element
 * (the key) in a sorted array. Binary search begins by examining the value in
 * the middle position of the array. - If the key is less than the middle
 * element, search the key in the first half of the array. - If the key is equal
 * to the middle element, the search ends with a match. The position is returned
 * - If the key is greater than the middle element, search the key in the second
 * half of the array.
 *
 * Compilation: javac BinarySearch.java Execution: java BinarySearch
 *
 * Output: the position of an element in a sorted array or -1 if the element is
 * not in the array
 *
 * Program Arguments: none
 *
 *********************************************/

public class BinarySearchRec {

    public static int linearSearch(int[] A, int target) {
        return linearSearchHelper(A, target, 0);
    }

    public static int linearSearchHelper(int[] A, int target, int index) {
        if (index >= A.length) {
            // BASE CASE: we've reached the end of the array without finding target
            return -1;
        } else if (A[index] == target) {
            // BASE CASE: we found target at index
            return index;
        } else {
            // RECURSIVE CASE: we haven't found target yet, so keep looking
            // in the rest of the array
            return linearSearchHelper(A, target, index + 1);
        }
    }

    public static int binarySearchHelper(int[] A, int target, int left, int right) {
        int middle = (right + left) / 2;

        if (left > right) {
            // BASE CASE 1: return -1 when there's no portion of the array remaining
            // where target can live in A
            return -1;
        } else if (target == A[middle]) {
            // BASE CASE 2: return the middle index when that's where the target lives.
            return middle;
        } else {
            // RECURSIVE CASE: there's still stuff left to search and the middle is not
            // where target lives.
            if (target < A[middle]) {
                return binarySearchHelper(A, target, left, middle - 1);
            } else { // target > A[middle], since it's not ==
                return binarySearchHelper(A, target, middle + 1, right);
            }
        }
    }

    // We write binarySearch to take the same arguments as iterative binary search
    // then use a helper function to handle the recursion
    public static int binarySearch(int[] A, int target) {
        return binarySearchHelper(A, target, 0, A.length - 1);
    }

    public static void main(String[] args) {
        int[] searchingArray = { 9, 10, 13, 15, 19, 27, 28, 28, 31, 39, 42, 43, 45, 53, 57, 66, 67, 85, 89, 92 };

        int target = 53;
        int targetPosition = binarySearch(searchingArray, target);
        System.out.println("Found " + target + " at position " + targetPosition + " using binary search.");

        int targetPosition2 = linearSearch(searchingArray, 89);
        System.out.println("Found " + target + " at position " + targetPosition2 + " using linear search.");
    }

}
