Commit 48072f21 by andrewlewis Committed by Oliver Woodman

Improve binary search functionality and javadoc.

Define what element is returned if inclusive is true and there are multiple
elements equal to the input value.

Clarify/fix javadoc.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=141891741
parent 41d078ca
...@@ -299,110 +299,167 @@ public final class Util { ...@@ -299,110 +299,167 @@ public final class Util {
} }
/** /**
* Returns the index of the largest value in an array that is less than (or optionally equal to) * Returns the index of the largest element in {@code array} that is less than (or optionally
* a specified value. * equal to) a specified {@code value}.
* <p> * <p>
* The search is performed using a binary search algorithm, so the array must be sorted. * The search is performed using a binary search algorithm, so the array must be sorted. If the
* array contains multiple elements equal to {@code value} and {@code inclusive} is true, the
* index of the first one will be returned.
* *
* @param a The array to search. * @param array The array to search.
* @param value The value being searched for. * @param value The value being searched for.
* @param inclusive If the value is present in the array, whether to return the corresponding * @param inclusive If the value is present in the array, whether to return the corresponding
* index. If false then the returned index corresponds to the largest value in the array that * index. If false then the returned index corresponds to the largest element strictly less
* is strictly less than the value. * than the value.
* @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than
* the smallest value in the array. If false then -1 will be returned. * the smallest element in the array. If false then -1 will be returned.
* @return The index of the largest element in {@code array} that is less than (or optionally
* equal to) {@code value}.
*/ */
public static int binarySearchFloor(int[] a, int value, boolean inclusive, boolean stayInBounds) { public static int binarySearchFloor(int[] array, int value, boolean inclusive,
int index = Arrays.binarySearch(a, value); boolean stayInBounds) {
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); int index = Arrays.binarySearch(array, value);
if (index < 0) {
index = -(index + 2);
} else {
while ((--index) >= 0 && array[index] == value) {}
if (inclusive) {
index++;
}
}
return stayInBounds ? Math.max(0, index) : index; return stayInBounds ? Math.max(0, index) : index;
} }
/** /**
* Returns the index of the largest value in an array that is less than (or optionally equal to) * Returns the index of the largest element in {@code array} that is less than (or optionally
* a specified value. * equal to) a specified {@code value}.
* <p> * <p>
* The search is performed using a binary search algorithm, so the array must be sorted. * The search is performed using a binary search algorithm, so the array must be sorted. If the
* array contains multiple elements equal to {@code value} and {@code inclusive} is true, the
* index of the first one will be returned.
* *
* @param a The array to search. * @param array The array to search.
* @param value The value being searched for. * @param value The value being searched for.
* @param inclusive If the value is present in the array, whether to return the corresponding * @param inclusive If the value is present in the array, whether to return the corresponding
* index. If false then the returned index corresponds to the largest value in the array that * index. If false then the returned index corresponds to the largest element strictly less
* is strictly less than the value. * than the value.
* @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than
* the smallest value in the array. If false then -1 will be returned. * the smallest element in the array. If false then -1 will be returned.
* @return The index of the largest element in {@code array} that is less than (or optionally
* equal to) {@code value}.
*/ */
public static int binarySearchFloor(long[] a, long value, boolean inclusive, public static int binarySearchFloor(long[] array, long value, boolean inclusive,
boolean stayInBounds) { boolean stayInBounds) {
int index = Arrays.binarySearch(a, value); int index = Arrays.binarySearch(array, value);
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); if (index < 0) {
index = -(index + 2);
} else {
while ((--index) >= 0 && array[index] == value) {}
if (inclusive) {
index++;
}
}
return stayInBounds ? Math.max(0, index) : index; return stayInBounds ? Math.max(0, index) : index;
} }
/** /**
* Returns the index of the smallest value in an array that is greater than (or optionally equal * Returns the index of the smallest element in {@code array} that is greater than (or optionally
* to) a specified value. * equal to) a specified {@code value}.
* <p> * <p>
* The search is performed using a binary search algorithm, so the array must be sorted. * The search is performed using a binary search algorithm, so the array must be sorted. If
* the array contains multiple elements equal to {@code value} and {@code inclusive} is true, the
* index of the last one will be returned.
* *
* @param a The array to search. * @param array The array to search.
* @param value The value being searched for. * @param value The value being searched for.
* @param inclusive If the value is present in the array, whether to return the corresponding * @param inclusive If the value is present in the array, whether to return the corresponding
* index. If false then the returned index corresponds to the largest value in the array that * index. If false then the returned index corresponds to the smallest element strictly
* is strictly less than the value. * greater than the value.
* @param stayInBounds If true, then {@code (a.length - 1)} will be returned in the case that the * @param stayInBounds If true, then {@code (a.length - 1)} will be returned in the case that the
* value is greater than the largest value in the array. If false then {@code a.length} will * value is greater than the largest element in the array. If false then {@code a.length} will
* be returned. * be returned.
* @return The index of the smallest element in {@code array} that is greater than (or optionally
* equal to) {@code value}.
*/ */
public static int binarySearchCeil(long[] a, long value, boolean inclusive, public static int binarySearchCeil(long[] array, long value, boolean inclusive,
boolean stayInBounds) { boolean stayInBounds) {
int index = Arrays.binarySearch(a, value); int index = Arrays.binarySearch(array, value);
index = index < 0 ? ~index : (inclusive ? index : (index + 1)); if (index < 0) {
return stayInBounds ? Math.min(a.length - 1, index) : index; index = ~index;
} else {
while ((++index) < array.length && array[index] == value) {}
if (inclusive) {
index--;
}
}
return stayInBounds ? Math.min(array.length - 1, index) : index;
} }
/** /**
* Returns the index of the largest value in an list that is less than (or optionally equal to) * Returns the index of the largest element in {@code list} that is less than (or optionally equal
* a specified value. * to) a specified {@code value}.
* <p> * <p>
* The search is performed using a binary search algorithm, so the list must be sorted. * The search is performed using a binary search algorithm, so the list must be sorted. If the
* list contains multiple elements equal to {@code value} and {@code inclusive} is true, the
* index of the first one will be returned.
* *
* @param <T> The type of values being searched. * @param <T> The type of values being searched.
* @param list The list to search. * @param list The list to search.
* @param value The value being searched for. * @param value The value being searched for.
* @param inclusive If the value is present in the list, whether to return the corresponding * @param inclusive If the value is present in the list, whether to return the corresponding
* index. If false then the returned index corresponds to the largest value in the list that * index. If false then the returned index corresponds to the largest element strictly less
* is strictly less than the value. * than the value.
* @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than
* the smallest value in the list. If false then -1 will be returned. * the smallest element in the list. If false then -1 will be returned.
* @return The index of the largest element in {@code list} that is less than (or optionally equal
* to) {@code value}.
*/ */
public static <T> int binarySearchFloor(List<? extends Comparable<? super T>> list, T value, public static <T> int binarySearchFloor(List<? extends Comparable<? super T>> list, T value,
boolean inclusive, boolean stayInBounds) { boolean inclusive, boolean stayInBounds) {
int index = Collections.binarySearch(list, value); int index = Collections.binarySearch(list, value);
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); if (index < 0) {
index = -(index + 2);
} else {
while ((--index) >= 0 && list.get(index).compareTo(value) == 0) {}
if (inclusive) {
index++;
}
}
return stayInBounds ? Math.max(0, index) : index; return stayInBounds ? Math.max(0, index) : index;
} }
/** /**
* Returns the index of the smallest value in an list that is greater than (or optionally equal * Returns the index of the smallest element in {@code list} that is greater than (or optionally
* to) a specified value. * equal to) a specified value.
* <p> * <p>
* The search is performed using a binary search algorithm, so the list must be sorted. * The search is performed using a binary search algorithm, so the list must be sorted. If the
* list contains multiple elements equal to {@code value} and {@code inclusive} is true, the
* index of the last one will be returned.
* *
* @param <T> The type of values being searched. * @param <T> The type of values being searched.
* @param list The list to search. * @param list The list to search.
* @param value The value being searched for. * @param value The value being searched for.
* @param inclusive If the value is present in the list, whether to return the corresponding * @param inclusive If the value is present in the list, whether to return the corresponding
* index. If false then the returned index corresponds to the smallest value in the list that * index. If false then the returned index corresponds to the smallest element strictly
* is strictly greater than the value. * greater than the value.
* @param stayInBounds If true, then {@code (list.size() - 1)} will be returned in the case that * @param stayInBounds If true, then {@code (list.size() - 1)} will be returned in the case that
* the value is greater than the largest value in the list. If false then {@code list.size()} * the value is greater than the largest element in the list. If false then
* will be returned. * {@code list.size()} will be returned.
* @return The index of the smallest element in {@code list} that is greater than (or optionally
* equal to) {@code value}.
*/ */
public static <T> int binarySearchCeil(List<? extends Comparable<? super T>> list, T value, public static <T> int binarySearchCeil(List<? extends Comparable<? super T>> list, T value,
boolean inclusive, boolean stayInBounds) { boolean inclusive, boolean stayInBounds) {
int index = Collections.binarySearch(list, value); int index = Collections.binarySearch(list, value);
index = index < 0 ? ~index : (inclusive ? index : (index + 1)); if (index < 0) {
index = ~index;
} else {
int listSize = list.size();
while ((++index) < listSize && list.get(index).compareTo(value) == 0) {}
if (inclusive) {
index--;
}
}
return stayInBounds ? Math.min(list.size() - 1, index) : index; return stayInBounds ? Math.min(list.size() - 1, index) : index;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment