二进制搜索变体(Java)中的无限循环

时间:2016-12-31 15:50:58

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

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

这是我的代码:

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是错误的。

3 个答案:

答案 0 :(得分:0)

您的算法似乎很好。但我发现为mid分配值存在问题。

int mid = (hi+lo)/2

想想你的情况

hi=4
mid = 3

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

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

在这种情况下,你可以做的是通过检查这个条件来增加mid的值。

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

相同

希望这会有所帮助..

祝你有愉快的一天.. :)

修改

更好的做法是

将您的while循环更改为

while(mid<hi+1){
 }

然后检查循环后值的相等性。

OR 只需设置

  mid = (mid+hi+1)/2

答案 1 :(得分:0)

样品溶液看起来很好。您的代码存在问题,mid = (lo + hi) / 2lo方向转,这是一个问题,因为更新案例为lo = midhi = mid - 1hi == lo + 1时,在第一种情况下,没有进展。你应该像样本一样向上舍入:mid = (lo + hi + 1) / 2(警告:可能在长数组上溢出;检查你的约束)。

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

答案 2 :(得分:0)

在你的循环中,你必须使你的间隔变小,你还必须排除你刚才看到的元素。你离开时会这样做,但是当你走右时却不这样做。

您还会错过长度为1的间隔,因为您使用包含的下限和上限。您的循环条件应为lo <= hi

最后,你返回太多:当键小于第一个元素时,结果应为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的数组在indoces 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;
}