From eb0d32f858dca27838541d6f30b1c1026c220d1d Mon Sep 17 00:00:00 2001 From: Ed Solovey <ed@digits.com> Date: Thu, 28 Sep 2023 00:08:32 -0400 Subject: [PATCH] More binary search implementations --- .../cs2223/algorithms/week1/ArraySearch.java | 11 ++++ .../{ => algorithms}/week1/BinarySearch.java | 24 ++++---- .../week1/BinarySearchRecursive.java | 40 +++++++++++++ .../cs2223/algorithms/week1/LinearSearch.java | 20 +++++++ .../week1/ArraySearchPerformanceTest.java | 52 ++++++++++++++++ .../algorithns/week1/ArraySearchTest.java | 60 +++++++++++++++++++ .../wpi/cs2223/week1/BinarySearchTest.java | 56 ----------------- 7 files changed, 196 insertions(+), 67 deletions(-) create mode 100644 src/edu/wpi/cs2223/algorithms/week1/ArraySearch.java rename src/edu/wpi/cs2223/{ => algorithms}/week1/BinarySearch.java (50%) create mode 100644 src/edu/wpi/cs2223/algorithms/week1/BinarySearchRecursive.java create mode 100644 src/edu/wpi/cs2223/algorithms/week1/LinearSearch.java create mode 100644 test/edu/wpi/cs2223/algorithns/week1/ArraySearchPerformanceTest.java create mode 100644 test/edu/wpi/cs2223/algorithns/week1/ArraySearchTest.java delete mode 100644 test/edu/wpi/cs2223/week1/BinarySearchTest.java diff --git a/src/edu/wpi/cs2223/algorithms/week1/ArraySearch.java b/src/edu/wpi/cs2223/algorithms/week1/ArraySearch.java new file mode 100644 index 0000000..5d4dfea --- /dev/null +++ b/src/edu/wpi/cs2223/algorithms/week1/ArraySearch.java @@ -0,0 +1,11 @@ +package edu.wpi.cs2223.algorithms.week1; + +/** + * Implements a search algorithm against an array of integers. + */ +public interface ArraySearch { + /** + * @return the index of target in sortedArray if it exists there. Otherwise -1; + */ + int find(int[] sortedArray, int target); +} diff --git a/src/edu/wpi/cs2223/week1/BinarySearch.java b/src/edu/wpi/cs2223/algorithms/week1/BinarySearch.java similarity index 50% rename from src/edu/wpi/cs2223/week1/BinarySearch.java rename to src/edu/wpi/cs2223/algorithms/week1/BinarySearch.java index c35917b..a28e4f5 100644 --- a/src/edu/wpi/cs2223/week1/BinarySearch.java +++ b/src/edu/wpi/cs2223/algorithms/week1/BinarySearch.java @@ -1,18 +1,20 @@ -package edu.wpi.cs2223.week1; +package edu.wpi.cs2223.algorithms.week1; /** * Implements the binary search algorithm against a sorted array of integers. + * Each iteration of the algorithm looks for the target at the midpoint index of the array, if the value at + * the midpoint is: + * <li>an exact match, then return midpoint</li> + * <li>less than the target, repeat the iteration on the right half of the current array</li> + * <li>greater than the target, repeat the iteration on the left half of the current array</li> */ -public class BinarySearch { - /** - * @return true iff the target value exists in sortedArray - */ - public boolean doesValueExist(int[] sortedArray, int target) { +public class BinarySearch implements ArraySearch { + public int find(int[] sortedArray, int target) { int loopIterations = 0; // empty arrays contain no targets if (sortedArray.length == 0) { - return returnWithLog(false, loopIterations, sortedArray.length); + return returnWithLog(-1, loopIterations, sortedArray.length); } int lowerRange = 0; @@ -25,7 +27,7 @@ public class BinarySearch { int valueAtMidPoint = sortedArray[midpoint]; if (target == valueAtMidPoint) { - return returnWithLog(true, loopIterations, sortedArray.length); + return returnWithLog(midpoint, loopIterations, sortedArray.length); } // narrow range to either left or right half based on comparison to midpoint @@ -35,11 +37,11 @@ public class BinarySearch { upperRange = midpoint - 1; } } - return returnWithLog(false, loopIterations, sortedArray.length); + return returnWithLog(-1, loopIterations, sortedArray.length); } - boolean returnWithLog(boolean returnValue, int loopIterations, int inputArrayLengths) { - System.out.printf("Returning %b after %d iterations for an array of size %d\n", returnValue, loopIterations, inputArrayLengths); + int returnWithLog(int returnValue, int loopIterations, int inputArrayLengths) { + System.out.printf("Returning %d after %d iterations for an array of size %d\n", returnValue, loopIterations, inputArrayLengths); return returnValue; } } diff --git a/src/edu/wpi/cs2223/algorithms/week1/BinarySearchRecursive.java b/src/edu/wpi/cs2223/algorithms/week1/BinarySearchRecursive.java new file mode 100644 index 0000000..5372b56 --- /dev/null +++ b/src/edu/wpi/cs2223/algorithms/week1/BinarySearchRecursive.java @@ -0,0 +1,40 @@ +package edu.wpi.cs2223.algorithms.week1; + +/** + * Implements binary array search recursively. + */ +public class BinarySearchRecursive implements ArraySearch{ + @Override + public int find(int[] sortedArray, int target) { + // empty array base case + if (sortedArray.length == 0) { + return -1; + } + + return find(sortedArray, target, 0, sortedArray.length -1, 0); + } + + int find(int[] sortedArray, int target, int low, int high, int iterations) { + if (low <= high) { + iterations++; + int midpoint = (high + low) / 2; + + if (sortedArray[midpoint] == target) { + System.out.printf("Found value in array of size %d after %d iteration.\n", sortedArray.length, iterations); + return midpoint; + } + + // recurse on the right half of the current range + if (target > sortedArray[midpoint]) { + return find(sortedArray, target, midpoint + 1, high, iterations); + } + + // recurse on the left half of the current range + return find(sortedArray, target, low, midpoint -1, iterations); + } + + // traversed array and did not find target + System.out.printf("Failed to find value in array of size %d after %d iteration.\n", sortedArray.length, iterations); + return -1; + } +} diff --git a/src/edu/wpi/cs2223/algorithms/week1/LinearSearch.java b/src/edu/wpi/cs2223/algorithms/week1/LinearSearch.java new file mode 100644 index 0000000..a6f6ca1 --- /dev/null +++ b/src/edu/wpi/cs2223/algorithms/week1/LinearSearch.java @@ -0,0 +1,20 @@ +package edu.wpi.cs2223.algorithms.week1; + +public class LinearSearch implements ArraySearch { + @Override + public int find(int[] sortedArray, int target) { + for (int index = 0; index < sortedArray.length; index++) { + if (sortedArray[index] == target) { + returnWithLog(index, index, sortedArray.length); + } + } + + // base case of empty array or case of us exhausting the array + return returnWithLog(-1, sortedArray.length, sortedArray.length); + } + + int returnWithLog(int returnValue, int loopIterations, int inputArrayLengths) { + System.out.printf("Returning %d after %d iterations for an array of size %d\n", returnValue, loopIterations, inputArrayLengths); + return returnValue; + } +} diff --git a/test/edu/wpi/cs2223/algorithns/week1/ArraySearchPerformanceTest.java b/test/edu/wpi/cs2223/algorithns/week1/ArraySearchPerformanceTest.java new file mode 100644 index 0000000..af3a5ed --- /dev/null +++ b/test/edu/wpi/cs2223/algorithns/week1/ArraySearchPerformanceTest.java @@ -0,0 +1,52 @@ +package edu.wpi.cs2223.algorithns.week1; + +import edu.wpi.cs2223.algorithms.week1.ArraySearch; +import edu.wpi.cs2223.algorithms.week1.BinarySearch; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class ArraySearchPerformanceTest { + ArraySearch search; + + static final List<Integer> PERFORMANCE_ARRAY_SIZES = + Arrays.asList( + (int) Math.pow(2, 12), + (int) Math.pow(2, 13), + (int) Math.pow(2, 14), + (int) Math.pow(2, 15) * 10, + (int) Math.pow(2, 15) * 100, + (int) Math.pow(2, 15) * 1000); + + @BeforeEach + public void setUp(){ + search = new BinarySearch(); +// search = new LinearSearch(); +// search = new BinarySearchRecursive(); + } + + @Test + public void measurePerformance(){ + for (int inputArraySize : PERFORMANCE_ARRAY_SIZES) { + int[] inputArray = generateRandomSortedArray(inputArraySize); + search.find(inputArray, new Random().nextInt()); + } + } + + /** + * Generate an array of sorted random integers of the specified size. + */ + int[] generateRandomSortedArray(int arraySize) { + Random randomGenerator = new Random(); + + List<Integer> input = new ArrayList<>(); + for (int generationIndex = 0; generationIndex < arraySize; generationIndex++) { + input.add(randomGenerator.nextInt()); + } + return input.stream().sorted().mapToInt(x -> x).toArray(); + } +} diff --git a/test/edu/wpi/cs2223/algorithns/week1/ArraySearchTest.java b/test/edu/wpi/cs2223/algorithns/week1/ArraySearchTest.java new file mode 100644 index 0000000..82c1e4e --- /dev/null +++ b/test/edu/wpi/cs2223/algorithns/week1/ArraySearchTest.java @@ -0,0 +1,60 @@ +package edu.wpi.cs2223.algorithns.week1; + +import edu.wpi.cs2223.algorithms.week1.ArraySearch; +import edu.wpi.cs2223.algorithms.week1.BinarySearchRecursive; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ArraySearchTest { + ArraySearch search; + + @BeforeEach + public void setUp(){ + search = new BinarySearchRecursive(); +// search = new BinarySearch(); +// search = new LinearSearch(); + } + + @Test + public void find_falseEmptyArray() { + int[] inputArray = new int[]{}; + assertEquals(-1, search.find(inputArray, 101)); + } + + @Test + public void find_false() { + int[] inputArray = new int[]{1, 9, 100, 564, 999}; + assertEquals(-1, search.find(inputArray, 101)); + } + + @Test + public void find_falseOutOfRangeLow() { + int[] inputArray = new int[]{1, 9, 100, 564, 999}; + assertEquals(-1, search.find(inputArray, -101)); + } + + @Test + public void find_falseOutOfRangeHigh() { + int[] inputArray = new int[]{1, 9, 100, 564, 999}; + assertEquals(-1, search.find(inputArray, 9001)); + } + + @Test + public void find_trueSingleValue() { + int[] inputArray = new int[]{1}; + assertEquals(0, search.find(inputArray, 1)); + } + + @Test + public void find_trueLeftOfMidpoint() { + int[] inputArray = new int[]{1, 9, 100, 564, 999}; + assertEquals(1, search.find(inputArray, 9)); + } + + @Test + public void find_trueRightOfMidpoint() { + int[] inputArray = new int[]{1, 9, 100, 564, 999}; + assertEquals(3, search.find(inputArray, 564)); + } +} \ No newline at end of file diff --git a/test/edu/wpi/cs2223/week1/BinarySearchTest.java b/test/edu/wpi/cs2223/week1/BinarySearchTest.java deleted file mode 100644 index d17cf84..0000000 --- a/test/edu/wpi/cs2223/week1/BinarySearchTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package edu.wpi.cs2223.week1; - - -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; - -class BinarySearchTest { - @Test - public void doesValueExist_falseEmptyArray(){ - int[] inputArray = new int[]{}; - - BinarySearch search = new BinarySearch(); - assertFalse(search.doesValueExist(inputArray, 101)); - } - - @Test - public void doesValueExist_false(){ - int[] inputArray = new int[]{ 1, 9, 100, 564, 999 }; - - BinarySearch search = new BinarySearch(); - assertFalse(search.doesValueExist(inputArray, 101)); - } - - @Test - public void doesValueExist_falseOutOfRangeLow(){ - int[] inputArray = new int[]{ 1, 9, 100, 564, 999 }; - - BinarySearch search = new BinarySearch(); - assertFalse(search.doesValueExist(inputArray, -101)); - } - - @Test - public void doesValueExist_falseOutOfRangeHigh(){ - int[] inputArray = new int[]{ 1, 9, 100, 564, 999 }; - - BinarySearch search = new BinarySearch(); - assertFalse(search.doesValueExist(inputArray, 9001)); - } - - @Test - public void doesValueExist_trueSingleValue(){ - int[] inputArray = new int[]{ 1}; - - BinarySearch search = new BinarySearch(); - assertTrue(search.doesValueExist(inputArray, 1)); - } - - @Test - public void doesValueExist_true(){ - int[] inputArray = new int[]{ 1, 9, 100, 564, 999 }; - - BinarySearch search = new BinarySearch(); - assertTrue(search.doesValueExist(inputArray, 9)); - } -} \ No newline at end of file -- GitLab