【问题标题】:Infinite loop in binary search variant (Java)二进制搜索变体(Java)中的无限循环
【发布时间】:2016-12-31 15:50:58
【问题描述】:

我的目标是输入一个键和一个数组,然后使用二进制搜索输出该数组中小于或等于该键的值的数量。

这是我的代码:

import java.util.*;
import java.io.*;

public class search {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int key = scan.nextInt();
        int size = scan.nextInt();
        int [] array = new int [size];

        for (int i = 0;i < size ;i++ ) {
            array[i] = scan.nextInt();
        }
        Arrays.sort(array);

        System.out.println(binary(key, array));
    }

    public static int binary (int key, int [] array){
        int lo = 0;
        int hi = array.length - 1;

        while (lo < hi){
            int mid = (lo + hi) / 2;
            if (array[mid] <= key){
                lo = mid;
            }

            else {
                hi = mid - 1;
            }
        }

        return lo + 1;
    }
}

数据键 = 5,数组 = {2,4,6,7},程序运行良好。但是一旦有 三个 值小于或等于键,它就会变得混乱。例如,key = 5, array = {2,4,5,6} 会产生一个无限循环。我已经找到了原因,但我不知道如何解决它。

基本上mid 值一直被计算为相同的值。我能做些什么来解决这个问题?如果代码本身就是错误的,那么这意味着the set solution for a USACO problem 是错误的。

【问题讨论】:

  • 用你的测试用例创建一个主目录。不要让我们这样做。

标签: java arrays algorithm infinite-loop binary-search


【解决方案1】:

示例解决方案看起来不错。您的代码的问题是mid = (lo + hi) / 2lo 舍入,这是一个问题,因为更新案例是lo = midhi = mid - 1。当hi == lo + 1,在第一种情况下,没有任何进展。您应该像示例一样四舍五入:mid = (lo + hi + 1) / 2(警告:长数组可能溢出;检查您的约束)。

示例还检查第一个值是否小于键。

【讨论】:

    【解决方案2】:

    您的算法看起来不错。但我发现为 mid 赋值存在问题。

    int mid = (hi+lo)/2
    

    想想你的

    hi=4
    mid = 3
    

    现在 mid 的新值将是 (3+4)/2 = 3(整数除法)

    所以循环将继续运行而不会中断。

    在这种情况下,您可以通过检查此条件来增加 mid 的值。

    但更有效的是,它似乎更好地检查 mid 的值是否重复,然后打破循环。 最后检查array[hi]的值是否和你的array[mid]一样

    希望这会有所帮助..

    祝你有美好的一天.. :)

    编辑

    更好的做法是

    把你的while循环改成

    while(mid<hi+1){
     }
    

    然后检查循环后的值是否相等..

    简单设置

      mid = (mid+hi+1)/2
    

    【讨论】:

      【解决方案3】:

      在你的循环中,你必须使你的间隔越来越小,你还必须排除你刚刚看过的元素。当你向左走时你会这样做,但当你向右走时不会这样做。

      您还错过了长度为 1 的区间,因为您使用了包含上下限。你的循环条件应该是lo &lt;= hi

      最后返回一个太多了:key小于第一个元素时返回0,大于最后一个元素时返回数组长度。

      所以:

      static int binary(int key, int[] array)
      {
          int lo = 0;
          int hi = array.length - 1;
      
          while (lo <= hi) {
              int mid = (lo + hi) / 2;
      
              if (array[mid] <= key) {
                  lo = mid + 1;
              } else {
                  hi = mid - 1;
              }
          }
      
          return lo;
      }
      

      在我看来,最好使用排他性上限,就像 Java 通常那样。 (例如,长度为n 的数组在索引0 到n - 1 处有元素,上限n 超出了有效范围。)如果没有别的,它与其他Java 代码一致。所以:

      static int binary(int key, int[] array)
      {
          int lo = 0;
          int hi = array.length;
      
          while (lo < hi) {
              int mid = (lo + hi) / 2;
      
              if (array[mid] <= key) {
                  lo = mid + 1;
              } else {
                  hi = mid;
              }
          }
      
          return lo;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-22
        • 1970-01-01
        • 2016-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-15
        • 1970-01-01
        相关资源
        最近更新 更多