【问题标题】:Java Binary searchJava 二进制搜索
【发布时间】:2010-02-28 20:25:36
【问题描述】:

尝试对 Book 对象的排序数组执行二进制搜索。

它不能很好地工作,它为某些对象返回正确的结果,但不是全部。

我在纸上进行了循环,似乎由于向上舍入 #.5 可能会遗漏一个数字。

任何想法如何使这项工作?

Book found = null;
    /*
     * Search at the center of the collection. If the reference is less than that,
     * search in the upper half of the collection, else, search in the lower half.
     * Loop until found else return null.
     */
    int top = numberOfBooks()-1;
    int bottom = 0;
    int middle;
    while (bottom <= top && found == null){
        middle = (bottom + top)/2;
        if (givenRef.compareTo(bookCollection.get(middle).getReference()) == 0) {
            found = bookCollection.get(middle);
        } else if (givenRef.compareTo(bookCollection.get(middle).getReference()) < 0){
            bottom = middle + 1;
        } else if (givenRef.compareTo(bookCollection.get(middle).getReference()) > 0){
            top = middle - 1;
        }
    }
    return found;

【问题讨论】:

  • 我将其添加到课程作业中。只需要一个标准搜索,但我也想包括一个二分搜索,让它在人群中脱颖而出

标签: java binary-search


【解决方案1】:

给你一些建议:

  • 没有必要保留Book 变量。在你的循环中,只要找到这本书就返回它,最后返回null。您还可以删除while 条件中变量的布尔检查。

  • middle 变量可以在循环内限定范围,无需延长它的寿命。

  • 你正在做bookCollection.get(middle).getReference() 三遍。考虑创建一个变量然后使用它。

  • middle = (bottom + top)/2 是二分搜索实现算法中的一个典型错误。甚至编写 Java Collection 类的 Joshua Bloch 也犯了这个错误(请参阅this interesting blog post 关于它)。相反,使用(bottom+top) &gt;&gt;&gt; 1,以避免非常大的值的整数溢出(你可能不会遇到这个错误,但这是为了原则)。

至于您的实际问题陈述,四舍五入将向下(整数除法),而不是向上。解决问题:

  • 您确定numberOfBooks() 方法与您的集合长度相对应吗?
  • 您确定compareTo() 方法对您使用的类型按预期工作吗(在您的代码示例中,我们不知道getReference() 返回类型是什么)
  • 您确定您的收藏按照getReference()正确排序了吗?
  • 最后,您确定使用givenRef.compareTo(bookCollection.get(middle).getReference()) &lt; 0 是正确的吗?在标准的二进制搜索实现中,它会被反转,例如bookCollection.get(middle).getReference().compareTo(givenRef) &lt; 0。这可能是 donroby 提到的,不确定。

在任何情况下,找出错误的方法是尝试不同的值,看看哪些输出正确,哪些不正确,从而推断出问题所在。如果您必须运行许多测试,您还可以使用调试器来帮助您逐步完成算法,而不是使用铅笔和纸。更好的是,正如 donroby 所说,编写一个单元测试。

【讨论】:

  • 我确定它会返回集合的大小,还有其他想法为什么它不能始终如一地工作吗?
【解决方案2】:

Collections.binarySearch() 怎么样?

【讨论】:

  • 我想自己写一个方法。不过谢谢
  • 自己实现算法是理解算法的好方法。在生产代码中,使用语言或库中可用的实现当然是个好主意。
【解决方案3】:

JRL 的所有建议都是正确的,但实际失败是您的比较被颠倒了。

我自己并没有立即看到这一点,但是将您的代码复制到一个函数中(使用字符串而不是 Books),编写一些简单的 Junit 测试然后在调试器中运行它们就非常明显了。

编写单元测试!

【讨论】:

  • 了解正在发生的事情的另一种策略是调试打印。我建议在循环内放置一些中间元素或索引的打印件,看看是否可以为您提供出错的线索。这或多或少是我在调试器中看到的......通过比较反转并且没有其他更改,它似乎适用于字符串。我唯一能想到的另一件事是,如果列表实际上没有排序,这肯定会意外失败。
【解决方案4】:

我发现了问题。

原来我是在对我的 bookCollection arrayList 进行二进制搜索,而不是我创建的新 sroted 数组 - sortedLib。

我犯了一个愚蠢的错误,但感谢您的意见和建议!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多