/* RecursiveAssignment.java requires java2 or higher */ import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.StringTokenizer; import java.util.Vector; /** * This class explores various recursive methods, as well as their iterative * counterparts. * * @author Zach Tomaszewski * @version 1.0 16 Sept 2001 * */ public class RecursiveAssignment { public static void main(String[] args) { int menuChoice = 9; StringBuffer bufferedString; StringTokenizer tokenedString; int[] arrayToSearch; int counter = 0; int answer, itemToFind, kSmallest; try{ /* a rather obscene use of the main method, but what better place to test the methods of that class? */ while (menuChoice != 0) { System.out.println("\n1. Recursive writeBackwards"); System.out.println("2. Iterative writeBackwards"); System.out.println("3. Recursive power"); System.out.println("4. Iterative power"); System.out.println("5. Recursive binarySearch"); System.out.println("6. Iterative binarySearch"); System.out.println("7. Recursive kthSmallest"); System.out.println("8. Iterative kthSmallest"); System.out.println("0. QUIT"); System.out.print("CHOOSE A METHOD TO TEST: "); BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); menuChoice = Integer.parseInt(stdin.readLine()); switch (menuChoice) { case 1: System.out.print("\nEnter a string to reverse: "); bufferedString = new StringBuffer(stdin.readLine()); writeBackwards(bufferedString); break; case 2: System.out.print("\nEnter a string to reverse: "); bufferedString = new StringBuffer(stdin.readLine()); iterativeWriteBackwards(bufferedString); break; case 3: try{ System.out.print("\nEnter a base number to raise: "); int base = Integer.parseInt(stdin.readLine()); System.out.print("Enter an exponent: "); int exponent = Integer.parseInt(stdin.readLine()); System.out.println("Answer: " + power(base, exponent)); }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); }catch (InvalidInputException iie) { System.out.println("This method does not accept" + " negative exponents."); } break; case 4: try{ System.out.print("\nEnter a base number to raise: "); int base = Integer.parseInt(stdin.readLine()); System.out.print("Enter an exponent: "); int exponent = Integer.parseInt(stdin.readLine()); System.out.println("Answer: " + iterativePower(base, exponent)); }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); }catch (InvalidInputException iie) { System.out.println("This method does not accept" + " negative exponents."); } break; case 5: try{ System.out.print("\nEnter an ORDERED sequence of numbers: "); tokenedString = new StringTokenizer(stdin.readLine(), " ,"); arrayToSearch = new int[tokenedString.countTokens()]; counter = 0; while (tokenedString.hasMoreTokens()){ arrayToSearch[counter] = Integer.parseInt(tokenedString.nextToken()); counter++; } System.out.print("Enter an integer to search for: "); itemToFind = Integer.parseInt(stdin.readLine()); answer = binarySearch(arrayToSearch, itemToFind); if (answer >= 0) { System.out.println("The integer is found at index " + answer + " in the array."); }else { System.out.println("The integer was not found in the array."); } }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); } break; case 6: try{ System.out.print("\nEnter an ORDERED sequence of numbers: "); tokenedString = new StringTokenizer(stdin.readLine(), " ,"); arrayToSearch = new int[tokenedString.countTokens()]; counter = 0; while (tokenedString.hasMoreTokens()){ arrayToSearch[counter] = Integer.parseInt(tokenedString.nextToken()); counter++; } System.out.print("Enter an integer to search for: "); itemToFind = Integer.parseInt(stdin.readLine()); answer = iterativeBinarySearch(arrayToSearch, itemToFind); if (answer >= 0) { System.out.println("The integer is found at index " + answer + " in the array."); }else { System.out.println("The integer was not found in the array."); } }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); } break; case 7: try{ System.out.print("\nEnter an sequence of numbers: "); tokenedString = new StringTokenizer(stdin.readLine(), " ,"); arrayToSearch = new int[tokenedString.countTokens()]; counter = 0; while (tokenedString.hasMoreTokens()){ arrayToSearch[counter] = Integer.parseInt(tokenedString.nextToken()); counter++; } System.out.print("Enter the kth smallest number to search for: "); kSmallest = Integer.parseInt(stdin.readLine()); answer = kthSmallest(arrayToSearch, kSmallest); System.out.println("The integer " + answer + " is the " + kSmallest + "th smallest in the array."); }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); }catch (InvalidInputException iie) { System.out.println("Results could not be computed " + "due to flawed input."); } break; case 8: try{ System.out.print("\nEnter an sequence of numbers: "); tokenedString = new StringTokenizer(stdin.readLine(), " ,"); arrayToSearch = new int[tokenedString.countTokens()]; counter = 0; while (tokenedString.hasMoreTokens()){ arrayToSearch[counter] = Integer.parseInt(tokenedString.nextToken()); counter++; } System.out.print("Enter the kth smallest number to search for: "); kSmallest = Integer.parseInt(stdin.readLine()); answer = iterativeKthSmallest(arrayToSearch, kSmallest); System.out.println("The integer " + answer + " is the " + kSmallest + "th smallest in the array."); }catch (NumberFormatException nfe) { System.out.println("Invalid numerical input."); }catch (InvalidInputException iie) { System.out.println("Results could not be computed " + "due to flawed input."); } break; default: menuChoice = 0; }//end switch }//end while }catch (IOException e) { System.out.println("I/O error!"); }catch (NumberFormatException nfe) { System.out.println("Invalid menu choice. Exiting..."); } } /** * Recursively reverses the given string and prints it to the screen. * * @param sb A StringBuffer to be reversed. */ public static void writeBackwards (StringBuffer sb){ if (sb.length() == 0) { return; }else if (sb.length() == 1) { System.out.println(sb.toString()); return; }else { System.out.print(sb.charAt(sb.length() - 1)); sb.deleteCharAt(sb.length() - 1); RecursiveAssignment.writeBackwards(sb); } } /** * Iteratively reverses the given string and prints it to the screen. * * @param sb A StringBuffer to be reversed. */ public static void iterativeWriteBackwards (StringBuffer sb){ for (int i = sb.length()-1; i >= 0; i--) { System.out.print(sb.charAt(i)); } System.out.println(); /* to end the line */ } /** * Recursively computes the result of the * first number to the power of the positive second; * prints the result to the screen. * * @param base The integer to be exponentially multiplied. * @param exponent The exponent to multiply by; must be zero or greater. * @return result The long result of this function. * @throws InvalidInputException when a negative exponent is submitted. */ public static long power (int base, int exponent) throws InvalidInputException{ long result = 1; if (exponent < 0) { throw new InvalidInputException("Negative exponent."); }else if (exponent == 0) { return 1; }else { return (base * RecursiveAssignment.power(base, --exponent)); } } /** * Iteratively computes the result of the * first number to the power of the second; * prints the result to the screen. * * @param base The integer to be exponentially multiplied. * @param exponent The exponent to multiply by; must be zero or greater. * @return A long containing the result * @throws InvalidInputException when a negative exponent is submitted. */ public static long iterativePower (int base, int exponent) throws InvalidInputException{ long result = 1; if (exponent < 0) { throw new InvalidInputException("Negative exponent."); }else if (exponent == 0) { return 1; } while (exponent > 0) { result *= base; exponent--; } return result; } /** * Performs a binary search through the passed, ordered int[] array * looking for the passed integer. Returns the index of the * found integer, or else -1 (NOTFOUND) if the integer is not in * the array. This version assumes that the whole array should be searched. * * @param arrayToSearch The int[] array to search through; * must be ordred from least to greatest. * @param itemToFind The int to look for in the array * @return Index of found integer, or -1 if not found */ public static int binarySearch (int[] arrayToSearch, int itemToFind) { return RecursiveAssignment.binarySearch(arrayToSearch, itemToFind, 0, arrayToSearch.length - 1); } /** * Performs a recursive binary search through the passed, ordered int[] * array looking for the passed integer. Returns the index of the * found integer, or else -1 (NOTFOUND) if the integer is not in * the array. This version of the method will search only that part * of the array delimited by the "first" and "last" parameters. * * @param arrayToSearch The int[] array to search through; * must be ordred from least to greatest. * @param itemToFind The int to look for in the array * @param first The array index to start searching at * @param last The array index to end searching at * @return Index of found integer, or -1 if not found */ public static int binarySearch(int[] arrayToSearch, int itemToFind, int first, int last){ int NOTFOUND = -1; int midpoint = (last + first)/2; if (first > last) { /* array size == 0 */ return NOTFOUND; }else if (first == last) { /* array size == 1 */ if (arrayToSearch[midpoint] == itemToFind) { return midpoint; }else { return NOTFOUND; } }else { if (arrayToSearch[midpoint] == itemToFind) { return midpoint; }else if (arrayToSearch[midpoint] > itemToFind) { last = midpoint - 1; /* take lower half of array */ return RecursiveAssignment.binarySearch(arrayToSearch, itemToFind, first, last); }else if (arrayToSearch[midpoint] < itemToFind) { first = midpoint + 1; return RecursiveAssignment.binarySearch(arrayToSearch, itemToFind, first, last); }else { //should never be needed, but needed to compile return NOTFOUND; } } } /** * Performs a binary search through the passed, ordered int[] array * looking for the passed integer. Returns the index of the * found integer, or else -1 (NOTFOUND) if the integer is not in * the array. This version assumes that the whole array should be searched. * * @param arrayToSearch The int[] array to search through; * must be ordred from least to greatest. * @param itemToFind The int to look for in the array * @return Index of found integer, or -1 if not found */ public static int iterativeBinarySearch (int[] arrayToSearch, int itemToFind) { return RecursiveAssignment.binarySearch(arrayToSearch, itemToFind, 0, arrayToSearch.length - 1); } /** * Performs an iterative binary search through the passed, ordered int[] * array looking for the passed integer. Returns the index of the * found integer, or else -1 (NOTFOUND) if the integer is not in * the array. This version of the method will search only that part * of the array delimited by the "first" and "last" parameters. * * @param arrayToSearch The int[] array to search through; * must be ordred from least to greatest. * @param itemToFind The int to look for in the array * @param first The array index to start searching at * @param last The array index to end searching at * @return Index of found integer, or -1 if not found */ public static int iterativeBinarySearch (int[] arrayToSearch, int itemToFind, int first, int last) { int NOTFOUND = -1; int midpoint = (last + first)/2; while (last > first) { if (arrayToSearch[midpoint] == itemToFind) { break; }else if (arrayToSearch[midpoint] > itemToFind) { last = midpoint - 1; /* take lower half of array */ continue; }else if (arrayToSearch[midpoint] < itemToFind) { first = midpoint + 1; continue; } } if (arrayToSearch[midpoint] == itemToFind) { return midpoint; }else { return NOTFOUND; } } /** * Searches the submitted array for the kth smallest integer therein, * where k is itself a positive integer. For example, the 3rd smallest * integer (k=3) of the array {1,3,10,7} would be 7. Arrays do not need * to be sorted. * * @param arrayToSearch The int[] to search * @param kSmallest The position to find * @return The kth smallest integer in the passed array * @throws InvalidInputException when k is not computable with * the passed array. */ public static int kthSmallest (int[] arrayToSearch, int kSmallest) throws InvalidInputException { Vector vectorToSearch = new Vector(arrayToSearch.length); for (int i = 0; i < arrayToSearch.length; i++) { vectorToSearch.addElement(new Integer(arrayToSearch[i])); } return kthSmallest(vectorToSearch, kSmallest); } /** * Searches the submitted vector of Integer objects for the kth smallest * integer therein, where k is itself a positive integer. For example, * the 3rd smallest integer (k=3) of the array {1,3,10,7} would be 7. * The vector does not need to be previously sorted. * * @param vectorToSearch The vector of Intger objects to search * @param kSmallest The position to find * @return The kth smallest integer in the passed array * @throws InvalidInputException when k is not computable with * the passed vector. */ public static int kthSmallest (Vector vectorToSearch, int kSmallest) throws InvalidInputException { int midrange = 0; //number of items that duplicate pivot value Integer intObject; int pivot, currentInt; if (kSmallest <= 0 || vectorToSearch.size() < kSmallest) { throw new InvalidInputException("k is <= 0 or exceeds the number" + " of elements in array."); }else if (vectorToSearch.size() == 1) { //from above, kSmallest must equal 1 here intObject = (Integer) vectorToSearch.elementAt(0); return intObject.intValue(); }else if (vectorToSearch.size() == 0) { throw new InvalidInputException("Cannot search an empty array."); } int pivotIndex = vectorToSearch.size() / 2; //pick a pivot number intObject = (Integer) vectorToSearch.elementAt(pivotIndex); pivot = intObject.intValue(); vectorToSearch.add(0, vectorToSearch.remove(pivotIndex)); pivotIndex = 0; for(int i=1; i < vectorToSearch.size(); i++) { intObject = (Integer) vectorToSearch.elementAt(i); currentInt = intObject.intValue(); if (currentInt < pivot) { vectorToSearch.add(0, vectorToSearch.remove(i)); pivotIndex++; }else if (currentInt > pivot) { //don't move bigger items, let them get pushed along }else { //then i == pivot duplicate vectorToSearch.add(pivotIndex + 1, vectorToSearch.remove(i)); midrange++; } } /* remember that pivotIndex is an index, while kSmallest is a count */ /* Hence, pivotCount */ int pivotCount = pivotIndex + 1; if (pivotCount <= kSmallest && kSmallest <= pivotCount + midrange){ //kSmallest is somewhere in the range of duplicate pivot values intObject = (Integer) vectorToSearch.elementAt(pivotIndex); return intObject.intValue(); }else if (pivotCount + midrange < kSmallest) { for (int i = 0; i<= pivotIndex + midrange; i++) { vectorToSearch.remove(0); } return kthSmallest(vectorToSearch, (kSmallest - (pivotCount + midrange))); }else if (pivotCount > kSmallest) { int i = 0; while(pivotIndex <= vectorToSearch.size() - 1) { vectorToSearch.remove(vectorToSearch.size() - 1); } return kthSmallest(vectorToSearch, kSmallest); }else{ throw new InvalidInputException(); //should never happen } } /** * Searches the submitted array for the kth smallest integer therein, * where k is itself a positive integer. For example, the 3rd smallest * integer (k=3) of the array {1,3,10,7} would be 7. Arrays do not need * to be sorted. * * @param arrayToSearch The int[] to search * @param kSmallest The position to find * @return The kth smallest integer in the passed array * @throws InvalidInputException when k is not computable with * the passed array. */ public static int iterativeKthSmallest (int[] arrayToSearch, int kSmallest) throws InvalidInputException { Vector vectorToSearch = new Vector(arrayToSearch.length); for (int i = 0; i < arrayToSearch.length; i++) { vectorToSearch.addElement(new Integer(arrayToSearch[i])); } return iterativeKthSmallest(vectorToSearch, kSmallest); } /** * Searches the submitted vector of Integer objects for the kth smallest * integer therein, where k is itself a positive integer. For example, * the 3rd smallest integer (k=3) of the array {1,3,10,7} would be 7. * The vector does not need to be previously sorted. * * @param vectorToSearch The vector of Intger objects to search * @param kSmallest The position to find * @return The kth smallest integer in the passed array * @throws InvalidInputException when k is not computable with * the passed vector. */ public static int iterativeKthSmallest (Vector vectorToSearch, int kSmallest) throws InvalidInputException { boolean notDone = true; while (notDone) { int midrange = 0; //number of items that duplicate pivot value Integer intObject; int pivot, currentInt; if (kSmallest <= 0 || vectorToSearch.size() < kSmallest) { throw new InvalidInputException("k is <= 0 or exceeds the number" + " of elements in array."); }else if (vectorToSearch.size() == 1) { //from above, kSmallest must equal 1 here intObject = (Integer) vectorToSearch.elementAt(0); return intObject.intValue(); }else if (vectorToSearch.size() == 0) { throw new InvalidInputException("Cannot search an empty array."); } int pivotIndex = vectorToSearch.size() / 2; //pick a pivot number intObject = (Integer) vectorToSearch.elementAt(pivotIndex); pivot = intObject.intValue(); vectorToSearch.add(0, vectorToSearch.remove(pivotIndex)); pivotIndex = 0; for(int i=1; i < vectorToSearch.size(); i++) { intObject = (Integer) vectorToSearch.elementAt(i); currentInt = intObject.intValue(); if (currentInt < pivot) { vectorToSearch.add(0, vectorToSearch.remove(i)); pivotIndex++; }else if (currentInt > pivot) { //don't move bigger items, let them get pushed along }else { //then i == pivot duplicate vectorToSearch.add(pivotIndex + 1, vectorToSearch.remove(i)); midrange++; } } /* remember that pivotIndex is an index, while kSmallest is a count */ /* Hence, pivotCount */ int pivotCount = pivotIndex + 1; if (pivotCount <= kSmallest && kSmallest <= pivotCount + midrange){ //kSmallest is somewhere in the range of duplicate pivot values intObject = (Integer) vectorToSearch.elementAt(pivotIndex); return intObject.intValue(); }else if (pivotCount + midrange < kSmallest) { for (int i = 0; i<= pivotIndex + midrange; i++) { vectorToSearch.remove(0); } kSmallest -= (pivotCount + midrange); }else if (pivotCount > kSmallest) { int i = 0; while(pivotIndex <= vectorToSearch.size() - 1) { vectorToSearch.remove(vectorToSearch.size() - 1); } } }//end while throw new InvalidInputException(); //should never happen } }//end class /** * An exception convenient for when a method recieved parameters it can't * handle, especially when those parameters are documented in the method's * description. */ class InvalidInputException extends Exception { public InvalidInputException() { super(); } public InvalidInputException(String s) { super(s); } }//end class