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
This commit is contained in:
andrewlewis 2016-12-13 08:00:28 -08:00 committed by Oliver Woodman
parent 41d078ca4b
commit 48072f2155

View file

@ -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)
* a specified value.
* Returns the index of the largest element in {@code array} that is less than (or optionally
* equal to) a specified {@code value}.
* <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 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
* is strictly less than the value.
* index. If false then the returned index corresponds to the largest element strictly less
* than the value.
* @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) {
int index = Arrays.binarySearch(a, value);
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1));
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)
* a specified value.
* <p>
* The search is performed using a binary search algorithm, so the array must be sorted.
*
* @param a The array to search.
* @param value The value being searched for.
* @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
* is strictly less than the value.
* @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.
*/
public static int binarySearchFloor(long[] a, long value, boolean inclusive,
public static int binarySearchFloor(int[] array, int value, boolean inclusive,
boolean stayInBounds) {
int index = Arrays.binarySearch(a, value);
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;
}
/**
* Returns the index of the smallest value in an array that is greater than (or optionally equal
* to) a specified value.
* Returns the index of the largest element in {@code array} that is less than (or optionally
* equal to) a specified {@code value}.
* <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 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
* is strictly less than the value.
* index. If false then the returned index corresponds to the largest element strictly less
* than the value.
* @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than
* 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[] array, long value, boolean inclusive,
boolean stayInBounds) {
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;
}
/**
* Returns the index of the smallest element in {@code array} that is greater than (or optionally
* equal to) a specified {@code value}.
* <p>
* 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 array The array to search.
* @param value The value being searched for.
* @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 smallest element strictly
* greater than the value.
* @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.
* @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) {
int index = Arrays.binarySearch(a, value);
index = index < 0 ? ~index : (inclusive ? index : (index + 1));
return stayInBounds ? Math.min(a.length - 1, index) : index;
int index = Arrays.binarySearch(array, value);
if (index < 0) {
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)
* a specified value.
* Returns the index of the largest element in {@code list} that is less than (or optionally equal
* to) a specified {@code value}.
* <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 list The list to search.
* @param value The value being searched for.
* @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
* is strictly less than the value.
* index. If false then the returned index corresponds to the largest element strictly less
* than the value.
* @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,
boolean inclusive, boolean stayInBounds) {
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;
}
/**
* Returns the index of the smallest value in an list that is greater than (or optionally equal
* to) a specified value.
* Returns the index of the smallest element in {@code list} that is greater than (or optionally
* equal to) a specified value.
* <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 list The list to search.
* @param value The value being searched for.
* @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
* is strictly greater than the value.
* index. If false then the returned index corresponds to the smallest element strictly
* greater than the value.
* @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()}
* will be returned.
* the value is greater than the largest element in the list. If false then
* {@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,
boolean inclusive, boolean stayInBounds) {
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;
}