【问题标题】:Implement binary search using the `Collections.binarySearch` signature使用 `Collections.binarySearch` 签名实现二进制搜索
【发布时间】:2016-10-23 04:57:21
【问题描述】:

这是我尝试实现必须遵循的二分搜索:

static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)

但是,我想避免代码重复并将其中一个实现委托给另一个实现(目前是第一个实现到第二个)。为此,我需要去掉通配符 ? 并使用第二个泛型类型,如下所示:

public class BinarySearch {
    public static <Q extends Comparable<? super T>, T>
    int search(List<Q> xs, T x) {
        return search(xs, x, Q::compareTo);
    }

    public static <T>
    int search(List<? extends T> xs, T x, Comparator<? super T> cmp) {
        int l = 0, r = xs.size() - 1;

        while (l <= r) {
            int mid = l + (r - l) / 2;

            if (cmp.compare(xs.get(mid), x) == 0)
                return mid;

            if (cmp.compare(xs.get(mid), x) < 0)
                r = mid - 1;
            else
                l = mid + 1;
        }

        return xs.size();
    }
}

不幸的是,这无法编译,失败并出现错误:

Non-static method cannot be referenced from a static context

我该如何解决这个问题?

PS:如果你想知道为什么来自 Collections 的签名看起来是这样的,这里有一个解释:How do these two generic signatures for Collections.binarySearch differ?

PPS:曾经有一个答案(现在已删除),您不能在预期 Comparator 的地方传递 T::compareTo。好吧,我相信你可以,这是我的 QuickSort 工作实现,它正是这样做的:https://github.com/all3fox/algos-java/blob/481f2c71952bf2c7510cb93cc1af8e90016ccf3b/src/main/java/io/github/all3fox/sort/QuickSort.java

【问题讨论】:

  • 您的二分搜索有更多问题。它缺少return 语句,以防找不到元素。
  • @Codo thx,已修复。那么泛型呢?

标签: java algorithm generics binary-search


【解决方案1】:

其实我不明白为什么要用Q:

public static <T extends Comparable<T>>
int search(List<? extends T> xs, T x) {
    return search(xs, x, T::compareTo);
}

将编译并在我看来足够了。 它让我可以做到这两点:

BinarySearch.search(new ArrayList<Timestamp>(), new Date());
BinarySearch.search(new ArrayList<Date>(), new Timestamp(0L));

这里非常重要的一点是,这实际上意味着(或多或少):

int search(List<? extends T> xs, final T x) {
    return search(xs, x, new Comparator<T>() {
      @Override
      public int compare(T o1, T o2) {
        return x.compareTo(o2);
      }
    });
}

现在我们可以清楚地看到:x 需要是 Comparable 类型。您的方法中没有说明这一点。相反,定义了一个类型 Q,但实际上没有参与者属于这种类型。所以 Comparator 不是严格兼容的,但它必须兼容,因为 x 的 compareTo 方法是比较器的实现。顺便说一句,另一种方法是使用Comparator.naturalOrder() 作为技巧,但仍然必须将 T 定义为 Comparable。

【讨论】:

  • 我已经更新了我的问题,链接到我之前的问题“为什么默认签名如此复杂”,这里是stackoverflow.com/questions/40195450/…
  • @all3fox 好的,我进行了编辑。但是还是没有Q...其实我没有看到你提到的问题中的Q。
  • 您已将extends Comparable&lt;T&gt; 边界移出返回值之前的参数列表。你能解释一下它有什么不同吗? (或指向文档)。这只是一个简写,以免在参数列表的两个地方写extends Comparable&lt;T&gt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多