Class BinarySearch
For sorted lists and arrays:
BinarySearch.inSortedArray([10, 20, 30, 40]).find(20)
=> Optional.of(1)
// Find the insertion point if not found
BinarySearch.inSortedList([10, 20, 30, 40]).insertionPointFor(22)
=> InsertionPoint.before(2)
// Search for double with a tolerance factor
// And find the range of all matches
BinarySearch.inSortedArrayWithTolerance([1.1, 2.1, 2.2, 2.3, 3.3, 4.4], 0.5).rangeOf(2)
=> Range.closed(1, 3)
To solve a monotonic polynomial function:
double polynomial(double x) {
return pow(x, 3) + 3 * x;
}
InsertionPoint<Double> solve(double y) {
return BinarySearch.forDoubles()
.insertionPointFor((low, mid, high) -> Double.compare(y, polynomial(mid)));
}
To find the minimum int value of a parabola:
double parabola(int x) {
return pow(x, 2) + 4 * x - 3;
}
int minimum = BinarySearch.forInts()
.insertionPointFor(
(low, mid, high) -> Double.compare(parabola(mid - 1), parabola(mid)))
.floor();
=> -2
To emulate the Guess The Number game:
BinarySearch.forInts()
.find((lo, mid, hi) -> tooHighOrTooLow(mid))
=> Optional.of(theGuessedNumber)
The forInts()
, forLongs()
, forDoubles()
and the primitive array search
methods perform no boxing in the O(logn) search operation.
Note that except inSortedList(List, Comparator)
, which may support null search
targets if the comparator supports nulls, no other BinarySearch.Table
implementations
allow null search targets.
- Since:
- 8.0
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic interface
Represents the search target that can be found through bisecting the double domain.static interface
Represents the search target that can be found through bisecting the integer domain.static interface
Represents the search target that can be found through bisecting the long integer domain.static class
BinarySearch.Table<K,
C extends Comparable<C>> Like a hash table, allows looking up comparable values by a key, except the lookup is through binary search instead of hashing. -
Method Summary
Modifier and TypeMethodDescriptionReturns aBinarySearch.Table
over all finite double values (exceptDouble.NaN
,Double.NEGATIVE_INFINITY
andDouble.POSITIVE_INFINITY
).forDoubles
(com.google.common.collect.Range<Double> range) Similar toforInts(Range)
, but returns aBinarySearch.Table
over the givenrange
ofdouble
precision numbers.forInts()
Returns aBinarySearch.Table
over all integers.Returns aBinarySearch.Table
over the givenrange
.forLongs()
static BinarySearch.Table
<Integer, Integer> inSortedArray
(int[] array) Returns aBinarySearch.Table
to search for array element indexes in the given sorted intarray
.static BinarySearch.Table
<Long, Integer> inSortedArray
(long[] array) Returns aBinarySearch.Table
to search for array element indexes in the given sorted longarray
.static BinarySearch.Table
<Double, Integer> inSortedArrayWithTolerance
(double[] array, double tolerance) Returns aBinarySearch.Table
to search for array element indexes in the given sorted doublearray
.static <E extends Comparable<E>>
BinarySearch.Table<E, Integer> inSortedList
(List<? extends E> list) Returns aBinarySearch.Table
to search for element indexes in the given sortedlist
.static <E> BinarySearch.Table
<E, Integer> inSortedList
(List<? extends E> list, Comparator<? super E> sortedBy) Returns aBinarySearch.Table
to search for element indexes in the given sortedlist
according tocomparator
.static <Q extends Comparable<Q>,
E>
BinarySearch.Table<Q, Integer> inSortedList
(List<? extends E> list, Function<? super E, ? extends Q> sortedBy) Returns aBinarySearch.Table
to search for element indexes in the givenlist
sorted by thesortBy
function.static BinarySearch.Table
<Double, Integer> inSortedListWithTolerance
(List<Double> list, double tolerance) Returns aBinarySearch.Table
to search for element indexes in the given list of sorteddouble
values.
-
Method Details
-
inSortedList
public static <E extends Comparable<E>> BinarySearch.Table<E,Integer> inSortedList(List<? extends E> list) Returns aBinarySearch.Table
to search for element indexes in the given sortedlist
.For example:
inSortedList(numbers).find(20)
.This is an O(1) operation.
- Parameters:
list
- expected to support random access (notLinkedList
for instance), or else performance will suffer.
-
inSortedList
public static <E> BinarySearch.Table<E,Integer> inSortedList(List<? extends E> list, Comparator<? super E> sortedBy) Returns aBinarySearch.Table
to search for element indexes in the given sortedlist
according tocomparator
.For example:
inSortedList(timestamps, nullsFirst(naturalOrder())).find(timestamp)
.This is an O(1) operation.
- Parameters:
list
- expected to support random access (notLinkedList
for instance), or else performance will suffer.
-
inSortedList
public static <Q extends Comparable<Q>,E> BinarySearch.Table<Q,Integer> inSortedList(List<? extends E> list, Function<? super E, ? extends Q> sortedBy) Returns aBinarySearch.Table
to search for element indexes in the givenlist
sorted by thesortBy
function.For example:
inSortedList(employees, Employee::age).rangeOf(20)
.This is an O(1) operation.
- Parameters:
list
- expected to support random access (notLinkedList
for instance), or else performance will suffer.
-
inSortedArray
Returns aBinarySearch.Table
to search for array element indexes in the given sorted intarray
.For example:
inSortedArray(numbers).find(20)
.This is an O(1) operation.
-
inSortedArray
Returns aBinarySearch.Table
to search for array element indexes in the given sorted longarray
.For example:
inSortedArray(largeNumbers).find(1000000000000L)
.This is an O(1) operation.
-
inSortedListWithTolerance
public static BinarySearch.Table<Double,Integer> inSortedListWithTolerance(List<Double> list, double tolerance) Returns aBinarySearch.Table
to search for element indexes in the given list of sorteddouble
values. The positivetolerance
is respected when comparing double values.For example:
inSortedListWithTolerance(temperatures, 0.1).find(30)
.This is an O(1) operation.
- Parameters:
list
- expected to support random access (notLinkedList
for instance), or else performance will suffer.tolerance
- an inclusive upper bound on the difference between the search target and elements in the list, which must be a non-negative finite value, i.e. notDouble.NaN
,Double.POSITIVE_INFINITY
, or negative, including-0.0
-
inSortedArrayWithTolerance
public static BinarySearch.Table<Double,Integer> inSortedArrayWithTolerance(double[] array, double tolerance) Returns aBinarySearch.Table
to search for array element indexes in the given sorted doublearray
. The positivetolerance
is respected when comparing double values.For example:
inSortedArrayWithTolerance(temperatures, 0.1).find(30)
.This is an O(1) operation.
-
forInts
Returns aBinarySearch.Table
over all integers.Callers can search by an
BinarySearch.IntSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.This is an O(1) operation.
-
forInts
public static BinarySearch.Table<BinarySearch.IntSearchTarget,Integer> forInts(com.google.common.collect.Range<Integer> range) Returns aBinarySearch.Table
over the givenrange
.Callers can search by an
BinarySearch.IntSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.While the common use cases of binary search is to search in sorted arrays and lists, there are diverse contexts where the algorithm is also applicable (think of the Guess the Number game). As a more realistic example, you can binary search a rotated, otherwise strictly-ordered array, using the following code:
Optional<Integer> binarySearchRotated(int[] rotated, int target) { return BinarySearch.forInts(Range.closedOpen(0, rotated.length)) find((low, mid, high) -> { int probe = rotated[mid]; if (target < probe) { return rotated[low] <= probe && target < rotated[low] ? 1 : -1; } else if (target > probe) { return probe <= rotated[high] && target > rotated[high] ? -1 : 1; } else { return 0; } }); }
This is an O(1) operation.
-
forLongs
Similar toforInts()
, but returns aBinarySearch.Table
over alllong
integers.Callers can search by a
BinarySearch.LongSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.For example, if we are to emulate the "Guess The Number" game, there will be a secret number and we can bisect the full long integer domain to find the number as in:
Optional<Long> guessed = forLongs().find((low, mid, high) -> Integer.compare(secret, mid)); assertThat(guessed).hasValue(secret);
This is an O(1) operation.
-
forLongs
public static BinarySearch.Table<BinarySearch.LongSearchTarget,Long> forLongs(com.google.common.collect.Range<Long> range) Similar toforInts(Range)
, but returns aBinarySearch.Table
over the givenrange
oflong
integers.Callers can search by a
BinarySearch.LongSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.This is an O(1) operation.
-
forDoubles
Returns aBinarySearch.Table
over all finite double values (exceptDouble.NaN
,Double.NEGATIVE_INFINITY
andDouble.POSITIVE_INFINITY
).Callers can search by an
BinarySearch.DoubleSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.Different from
inSortedArrayWithTolerance(double[], double)
, which is to search within the int indexes of a double array, this method searches through double values.You can use binary search to solve monotonic functions. For example the following method solves cube root:
BinarySearch.Table<Double, Double> cubeRoot() { return forDoubles() .by(cube -> (low, mid, high) -> Double.compare(cube, mid * mid * mid)); } cubeRoot().insertionPointFor(125.0) => InsertionPoint.at(5.0)
This is an O(1) operation.
-
forDoubles
public static BinarySearch.Table<BinarySearch.DoubleSearchTarget,Double> forDoubles(com.google.common.collect.Range<Double> range) Similar toforInts(Range)
, but returns aBinarySearch.Table
over the givenrange
ofdouble
precision numbers.Callers can search by a
BinarySearch.DoubleSearchTarget
object that will be called at each probe to determine whether the target is already found at the current mid-point, to the left half of the current subrange, or to the right half of the current subrange.For example you can implement square root through binary search:
BinarySearch.Table<Double, Double> sqrt() { return forDoubles(atLeast(0D)) .by(square -> (low, mid, high) -> Double.compare(square, mid * mid)); } sqrt().insertionPointFor(25.0) => InsertionPoint.at(5.0)
Infinite endpoints are disallowed.
This is an O(1) operation.
-