我努力让这个工作起来。我需要编写一个函数,它将使用binarySearch算法来查找长度在12到15个单位之间的梯形图。
这是二元搜索:
public static <AnyType> int binarySearch(GenericSimpleArrayList<AnyType> a, AnyType x, Comparator<? super AnyType> cmp) {
int low = 0;
int high = a.size() - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (cmp.compare(a.get(mid), x) < 0) {
low = mid + 1;
} else if (cmp.compare(a.get(mid), x) > 0) {
high = mid - 1;
} else {
return mid;
}
}
return NOT_FOUND; // NOT_FOUND = -1
}
这就是我对仿函数的所作所为:
public class FindLadder implements Comparator<Ladder>{
@Override
public int compare(Ladder lhs, Ladder rhs) {
return 0;
}
}
现在很明显,仿函数目前还没有做任何事情,我不知道要在仿函数中放什么以确定梯子是否落在x和x长度之间,我也不知道如何实现binarySearch方法。我需要将一个Ladder对象作为x传递,以便仿函数可以工作,据我所知,但是我如何规定我要搜索的长度? Ladder类有一个.length()方法。
数组按最短到最长的顺序排序。我根本无法更改binarySearch代码。我只能实现一个能满足我需要的仿函数。
答案 0 :(得分:2)
框架有built-in binary search和generic
List<T>
interface,您应该使用它们。
内置binarySearch
函数始终将pivot元素作为第二个参数提供给比较器。这是未记录的行为,但我们可以使用以下比较器来利用它:
public static class FindLadderInterval implements Comparator<Ladder> {
public final int min, max;
public FindLadderInterval(int min, int max) {
this.min = min;
this.max = max;
}
@Override
public int compare(Ladder lhs, Ladder rhs) {
// ignore rhs
int length = lhs.length();
return length < this.min ? -1 : length > this.max ? 1 : 0;
}
}
然后你可以这样使用它:
int index = Collections.binarySearch(list, null, new FindLadderInterval(12, 15));
工作示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main2 {
public static class Ladder {
private final int _length;
public Ladder(int length) {
this._length = length;
}
public int length() {
return this._length;
}
@Override
public String toString() {
return "Ladder(" + this._length + ")";
}
}
public static class FindLadderInterval implements Comparator<Ladder> {
public final int min, max;
public FindLadderInterval(int min, int max) {
this.min = min;
this.max = max;
}
@Override
public int compare(Ladder lhs, Ladder rhs) {
// ignore rhs
int length = lhs.length();
return length < this.min ? -1 : length > this.max ? 1 : 0;
}
}
public static void main(String[] args) {
List<Ladder> list = new ArrayList<Ladder>();
list.add(new Ladder(1));
list.add(new Ladder(2));
list.add(new Ladder(6));
list.add(new Ladder(13));
list.add(new Ladder(17));
list.add(new Ladder(21));
int index = Collections.binarySearch(list, null,
new FindLadderInterval(12, 15));
System.out.println("index: " + index);
System.out.println("ladder: " + list.get(index));
}
}
在间隔中查找元素的任务不是简单的二进制搜索,但我们可以使用类似于内置函数的binarySearch
函数来实现它,因为它返回插入索引< / em>如果找不到元素,则为负数。因此,我们可以在间隔结束时搜索元素,如果找到则返回它,如果找不到,只需检查插入索引处的项是否在间隔中,然后返回。这样算法将返回区间中的最后一个元素。
public static <T, R extends Comparable<? super R>> int intervalBinarySearchBy(
List<T> list, R min, R max, Function<? super T, ? extends R> selector) {
int idx = binarySearchBy(list, max, selector);
if (idx >= 0) return idx;
// Collections.binarySearch returns the insertion index binary
// negated if the element was not found
idx = ~idx;
return (idx < list.size()
&& min.compareTo(selector.apply(list.get(idx))) <= 0) ? idx : -1;
}
要使用内置的Collections.binarySearch
或您的函数,您需要提供代表性元素,例如,按照长度排序字符串时,这非常困难。要查找长度为15的字符串,您必须提供长度为15的字符串。这就是为什么我更喜欢python样式排序,它使用键函数或选择器 。基本上,您不需要比较,而是需要映射到可比较的值。例如,从String
到Integer
的映射,例如s -> s.length()
。这使得实现像这样的甜函数成为可能(lambdas使它漂亮):
List<Person> list = getPersons();
Person youngest = minBy(list, p -> p.getAge());
Person tallest = maxBy(list, p -> p.getHeight());
Person person42 = findBy(list, 42, p -> p.getAge());
sortBy(list, p -> p.getAge());
请参阅,不需要Comparator
按属性订购商品。任务简单,解决方案简单。不幸的是,我不知道标准库或第三方中的这类功能。但它们可以实施。
Java 8中的一个工作示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class Main {
public static class Collections2 {
/**
* Mimics Collections.binarySearch
*
* @param list
* @param pivotKey
* @param selector
* @return
*/
public static <T, R extends Comparable<? super R>> int binarySearchBy(
List<T> list, R pivotKey,
Function<? super T, ? extends R> selector) {
int low = 0;
int high = list.size() - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int ord = selector.apply(list.get(mid)).compareTo(pivotKey);
if (ord < 0) {
low = mid + 1;
} else if (ord > 0) {
high = mid - 1;
} else {
return mid;
}
}
return ~high; // bitwise negated insertion point /* -(a+1) == ~a */
}
/**
* Finds the index of the last element in the interval, or returns -1 if
* no such element was found.
*
* @param list
* @param min
* @param max
* @param selector
* @return
*/
public static <T, R extends Comparable<? super R>> int intervalBinarySearchBy(
List<T> list, R min, R max, Function<? super T, ? extends R> selector) {
int idx = binarySearchBy(list, max, selector);
if (idx >= 0) return idx;
// Collections.binarySearch returns the insertion index binary
// negated if the element was not found
idx = ~idx;
return (idx < list.size()
&& min.compareTo(selector.apply(list.get(idx))) <= 0) ? idx : -1;
}
public static <T, R extends Comparable<? super R> > Comparator<T> comparatorBy(
Function<? super T, ? extends R> selector) {
return (a, b) -> selector.apply(a).compareTo(selector.apply(b));
}
}
public static Function<Ladder, Integer> LENGTH_OF = a -> a.length();
public static class Ladder {
private final int _length;
public Ladder(int length) {
this._length = length;
}
public int length() {
return this._length;
}
@Override
public String toString() {
return "Ladder(" + this._length + ")";
}
}
public static void main(String[] args) {
List<Ladder> list = new ArrayList<Ladder>();
list.add(new Ladder(5));
list.add(new Ladder(9));
list.add(new Ladder(14));
list.add(new Ladder(7));
list.add(new Ladder(22));
list.add(new Ladder(23));
list.add(new Ladder(11));
list.add(new Ladder(9));
Collections.sort(list, Collections2.comparatorBy(LENGTH_OF));
int i = 0;
for (Ladder s : list) {
System.out.println("" + (i++) + ": " + s);
}
int foundIdx = Collections2.intervalBinarySearchBy(list, 12, 15,
LENGTH_OF);
System.out.println("Index: " + foundIdx);
System.out.println(list.get(foundIdx));
}
}
答案 1 :(得分:1)
试试这个:
public class FindLadder implements Comparator<Ladder>{
@Override
public int compare(Ladder lhs, Ladder rhs) {
if(lhs.length() < rhs.length() && lhs.length() > 12) // Suppose rhs.length() is 15
{
return 0;
}
if(lhs.length() < 12) {
return -1;
}
else {
return 1;
}
}
}
使用x = 15调用binarySearch()
。与LibraryComparator.binarySearch(l, new Ladder(15), new FindLadder());
我硬编码12
。别无他法。
答案 2 :(得分:0)
您显然希望/需要实现自己的二进制搜索,但我还是要引用内置方法。
来自Collections.binarySearch(List, T, Comparator)的javadoc:
返回搜索键的索引(如果它包含在列表中);否则,
(-(insertion point) - 1)
。 插入点定义为将密钥插入列表的点:第一个元素的索引大于键,或list.size()
如果列表中的所有元素都是小于指定的键。请注意,当且仅当找到密钥时,这可以保证返回值>> =。
这里的关键是插入点,或者换句话说,返回的索引指向第一个元素>&gt; =搜索值,或size()
如果没有这样的元素存在。没有NOT_FOUND
返回值。
由于您需要12
和15
之间的值,请搜索12
,然后验证您是否找到了值并且该值为&lt; = 15
。
答案 3 :(得分:0)
确保binarySearch算法的前提条件:
然后试试这个
public int compare(Ladder lhs, Ladder rhs) {
boolean isLhsInRange = lhs.length() >= 12 && lhs.length() <= 15;
boolean isRhsInRange = rhs.length() >= 12 && rhs.length() <= 15;
if(isLhsInRange && isRhsInRange) return 0;
else return lhs.length() - rhs.length();
}