/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl.time;
import java.util.List;
/**
* Generic binary search that can accepts lists of Java objects that can be
* adapted to a double value for searching.
*
* @author bdferris
*
*/
public class GenericBinarySearch {
/**
* Return an index into the element list such that if a new element with the
* specified target value was inserted into the list at the specified index,
* the list would remain in sorted order with respect to the
* {@link ValueAdapter}
*
* @param elements a list of objects, sorted in the order appropriate to the
* {@link ValueAdapter}
* @param targetValue target value to search for
* @param valueAdapter adapter to convert the input element type into a double
* value
* @return
*/
public static <T> int search(List<T> elements, double targetValue,
ValueAdapter<T> valueAdapter) {
return search(elements, targetValue, valueAdapter, 0, elements.size());
}
/**
* Return an index into the element list such that if a new element with the
* specified target value was inserted into the list at the specified index,
* the list would remain in sorted order with respect to the
* {@link ValueAdapter}
*
* @param elements a list of objects, sorted in the order appropriate to the
* {@link ValueAdapter}
* @param targetValue target value to search for
* @param valueAdapter adapter to convert the input element type into a double
* value
* @return
*/
public static <T> int search(T elements, int size, double targetValue,
IndexAdapter<T> valueAdapter) {
return search(elements, targetValue, valueAdapter, 0, size);
}
/**
* Return an index into the element list such that if a new element with the
* specified target value was inserted into the list at the specified index,
* the list would remain in sorted order with respect to the
* {@link IndexAdapter}
*
* @param elements a collection of objects, sorted in the order appropriate to
* the {@link IndexAdapter}
* @param indexFrom starting index range
* @param indexTo ending index range
* @param targetValue target value to search for
* @param valueAdapter adapter to convert the input element type into a double
* value
* @return
*/
public static <T> int searchRange(T elements, int indexFrom, int indexTo,
double targetValue, IndexAdapter<T> valueAdapter) {
return search(elements, targetValue, valueAdapter, indexFrom, indexTo);
}
public interface ValueAdapter<T> {
public double getValue(T value);
}
public interface IndexAdapter<T> {
public double getValue(T source, int index);
}
/****
* Private Methods
****/
private static <T> int search(List<T> elements, double target,
ValueAdapter<T> comparator, int fromIndex, int toIndex) {
if (fromIndex == toIndex)
return fromIndex;
int midIndex = (fromIndex + toIndex) / 2;
T element = elements.get(midIndex);
double v = comparator.getValue(element);
if (target < v) {
return search(elements, target, comparator, fromIndex, midIndex);
} else if (target > v) {
return search(elements, target, comparator, midIndex + 1, toIndex);
} else {
return midIndex;
}
}
private static <T> int search(T elements, double target,
IndexAdapter<T> adapter, int fromIndex, int toIndex) {
if (fromIndex == toIndex)
return fromIndex;
int midIndex = (fromIndex + toIndex) / 2;
double v = adapter.getValue(elements, midIndex);
if (target < v) {
return search(elements, target, adapter, fromIndex, midIndex);
} else if (target > v) {
return search(elements, target, adapter, midIndex + 1, toIndex);
} else {
return midIndex;
}
}
}