diff --git a/src/main/scala/Search/BinarySearch.scala b/src/main/scala/Search/BinarySearch.scala index 16458c2..70cafe3 100644 --- a/src/main/scala/Search/BinarySearch.scala +++ b/src/main/scala/Search/BinarySearch.scala @@ -44,4 +44,46 @@ object BinarySearch { SearchImpl(fromIndex, toIndex-1) } + + /** + * unbounded binary search to search element in infinite array + * + * An Infinite array is an array whose size is unknown but given an + * index i, we can get the element at that index + * @param arr an infinite stream of integers + * @param elem a integer to search for in the @args + * @return index of the @elem otherwise throws [[IndexOutOfBoundsException]] + * + * @throws IndexOutOfBoundsException if elem is not found in infinite arr or array is finite + */ + def unboundedBinarySearch(arr: Stream[Int], elem: Int): Int = { + + var fromIndex = 0 + var toIndex = 1 //2^0 + var _elem = arr(fromIndex) + + // a log n loop to find start and end index to apply binary search + // NOTE: not checking index out of bound assuming array is infinite + while (_elem < elem){ + fromIndex = toIndex + toIndex = 2 * toIndex + _elem = arr(toIndex) + } + + @tailrec + def SearchImpl(lo: Int, hi: Int): Int = { + if (lo > hi) + -1 + else { + val mid: Int = lo + (hi - lo) / 2 + arr(mid) match { + case mv if (mv == elem) => mid + case mv if (mv <= elem) => SearchImpl(mid + 1, hi) + case _ => SearchImpl(lo, mid - 1) + } + } + } + + SearchImpl(fromIndex, toIndex) + } } \ No newline at end of file diff --git a/src/test/scala/Search/BinarySearchSpec.scala b/src/test/scala/Search/BinarySearchSpec.scala index 2c86ab8..1cb0854 100644 --- a/src/test/scala/Search/BinarySearchSpec.scala +++ b/src/test/scala/Search/BinarySearchSpec.scala @@ -32,4 +32,17 @@ class BinarySearchSpec extends FlatSpec { assert(BinarySearch.binarySearch(l,7,0,4) === -1) assert(BinarySearch.binarySearch(l,7,1,3) === -1) } + + "An Unbounded Binary Search With Range" should "return the index of an element in an array" in { + val l = Stream.range(1,100) + assert(BinarySearch.unboundedBinarySearch(l,2) === 1) + assert(BinarySearch.unboundedBinarySearch(l,5) === 4) + } + + "An Unbounded Binary Search" should "fail if you are finding corner element and array is not infinite" in { + val l = Stream.range(1,100) + intercept[IndexOutOfBoundsException]( + BinarySearch.unboundedBinarySearch(l, 99) + ) + } }