在java中使用递归进行二进制搜索

时间:2014-08-29 21:24:16

标签: java recursion binary-search

我正在为递归二进制搜索编写程序。我有一个输入文件,其中包含一系列已排序的数字,我将其添加到ArrayList中。程序搜索以查看用户输入给出的键是否在ArrayList中。

public static int binarySearch(int key, int median){
    if(key == (int)array.get(median)){
        return key;
    }else if(key < (int)array.get(median)){
        binarySearch(key,median-1);
    }else if(key > (int)array.get(median)){
        binarySearch(key,median+1);
    }
    return -1;
}

例如,假设键是90.我调试并将watch放在key和array.get(中位数)处。在单步执行程序之后,我发现即使key和array.get(中位数)等于90,程序也会继续循环而不返回密钥。我知道递归并不是理想的,但这是我需要使用的。

5 个答案:

答案 0 :(得分:2)

这看起来不像正确的二进制搜索,因为二进制搜索使用分而治之的方法。您最初只划分一次列表,然后从那里检查每个元素。最好再次划分列表,依此类推,请参阅https://en.wikipedia.org/wiki/Binary_search_algorithm

无论如何,为了让你的代码运行,为什么你没有得到结果很可能是因为你没有返回递归的结果,而是返回-1。

删除return -1并在递归binarySearch调用之前设置一个返回值。当你找不到元素时,你会错过一个退出条件。

示例(仍然不是正确的二进制搜索):

public static int binarySearch(int key, int median){
    if (median < 0 || median > array.size() - 1) { // element not found
        return -1;
    }
    if (key == (int)array.get(median)){
        return key;
    } else if(key < (int)array.get(median)){
        return binarySearch(key,median-1);
    } else{
        return binarySearch(key,median+1);
    }
}

答案 1 :(得分:1)

如果您关心的是它是否在数据结构中......

public static boolean binarySearch(int key, int median){

    if(key == (int)array.get(median)){
        return true;
    }else if(key < (int)array.get(median)){
        return binarySearch(key,median-1);
    }else if(key > (int)array.get(median)){
        return binarySearch(key,median+1);
    }
}

您的代码可以更好地编写,但复制到其中以了解其中的重要部分

答案 2 :(得分:1)

您应该像这样更改代码:

public static int binarySearch(int key, int median){
if(key == (int)array.get(median)){
    return key;
}else if(key < (int)array.get(median)){
    return binarySearch(key,median-1);
}else if(key > (int)array.get(median)){
    return binarySearch(key,median+1);
}
return -1;
}

如果你这样做,你的递归会结束,但我会留给你测试你的二进制搜索代码。在此方法中有一些事情,比如你要忽略的起始索引和结束索引应该添加return语句,因为如果你没有控制移动到方法中的下一个语句,这是不合需要的。希望有所帮助!

答案 3 :(得分:1)

发布的代码 a Binary Search,实际上是使用递归的线性搜索。二进制搜索将搜索空间分成两半每一步,二进制意味着“两半”在上下文中。结果是此线性搜索在O(n)中运行,而不是二进制搜索的预期O(lg n)边界

问题/问题(除了是二进制搜索):

  • 递归案例中的值丢失,因为它们本身并未返回。递归情况的结果必须以某种方式使用(或者为什么要调用该函数?)。在这种情况下,应该直接返回值,例如。 return binarySearch(..)。这导致“继续循环而不返回密钥” - 它实际上 找到密钥,但丢弃了递归结果。

  • 代码无法正确检测越界终端条件。当找不到密钥时,这可能导致IndexOutOfBoundsException。

  • 如果没有其他逻辑,步骤左/右方法可能永远不会正确终止。例如,当列表是{1,3,5,7}并且所寻找的值是4时,原始代码将在索引1(值3)和2(值4)之间乒乓。这将导致抛出StackOverflowError。

  • 返回密钥。这没有多大意义,因为密钥已经知道,它也可以防止-1被检测到。返回找到的索引,如果只需要存在测试,则返回布尔值。

花点时间了解并解决这些问题..如果需要,请继续阅读剧透。


考虑这个重写修复上面列出的问题。请注意,它仍然是过于复杂 1 ,同时仍采用较差的算法和O(n)性能。无论如何;

// By taking in the List we make this function universal and not
// dependent upon a static field. It should probably take in a List<Integer>
// but I don't know what the actual type of "array" is. A more advanced
// implementation would take in List<Comparable> and then be modified to work
// with any objects that correctly implement said interface.
public static int linearSearch(int key, List list, int index, int step) {
    if (index < 0 || index >= list.size()) {
       // Base case: not found, out of bounds
       return -1;
    }

    int x = (int)list.get(index);
    if (key < x && step <= 0) {       // need to look left, NOT looking right
        // Recursive case: look left, returning result
        return linearSearch(key, list, index - 1, -1);
    } else if (key > x && step >= 0){ // need to look right, NOT looking left
        // Recursive case: look right, returning result
        return linearSearch(key, list, index + 1, +1);
    } else if (key == x) {
        // Base case: found key, return index found
        return index;  
    } else {
        // Base case: key not equal, refusing to ping-pong
        return -1;
    }
}

然后考虑使用这个帮助器/包装器函数;

// Returns the index in "array" where key was found, or -1 if it was not found
public static int linearSearch(int key) {
    // Have to start somewhere, might as well be the middle..
    // ..but it does NOT make the time complexity any better
    // ..and it is still NOT a Binary Search.
    return linearSearch(key, array, array.size() / 2, 0);
}

1 或者,因为它线性搜索,所以可以在没有额外的左/右移动的情况下重写它并且具有相同的复杂边界。 (将这个更简单的代码修改为recursive Binary Search也很简单。)

public static int linearSearch(int key, List list, int index) {
    if (index >= list.size() {
        // Base case: end of list
        return -1;
    }

    int x = (int)list.get(index);
    if (key < x) {
        // Recursive case: not there yet, keep looking
        return linearSearch(key, list, index + 1);
    } else if (key == x) {
        // Base case: found key, return index
        return index;
    } else { // -> key > x
        // Base case: read past where the key would be found
        return -1;
    }
}

答案 4 :(得分:0)

这里是ArrayList<Integer>的二进制搜索:)

public int binarySearch(List<Integer> list, int find) {
    int mid = list.size() / 2;
    int val = list.get(mid);

    if (val == find) {
        return val;
    } else if (list.size() == 1) {
        return -1;
    }

    return val > find ?
        binarySearch(list.subList(0, mid), find) :
        binarySearch(list.subList(mid, list.size()), find);
}