我可以获得有关失败的二进制搜索实现的反馈吗?

时间:2016-08-19 13:12:04

标签: javascript

我的目标是编写一个indexOf函数,该函数使用二进制搜索来查找数组中所需元素的索引。

我的问题是,编写一个递归解决方案,我总是吹掉调用堆栈 - 即使在绝对很小的数组中。我的期望是,即使是非尾调用优化语言的二进制搜索也不应该为任何不是 monstrous 大的数组吹掉调用堆栈。

在英文/伪代码中,我的想法是

  • 采用seekValue和arrayToSearch
  • middle为数组的长度除以2,向下舍入
  • currentValue成为数组中间的任何内容(又名arrayToSearch[middle]
  • 如果currentValue与seekValue相同,则返回middle
  • 如果currentValue小于seekValue,则在此数组的后半部分递归调用此函数
  • 如果currentValue大于seekValue,则在此数组的前半部分递归调用此函数
  • 最终我们将登陆正确的价值并将其归还

以下是我在JS中写的方式:

function indexOf(soughtValue, arrayToSearch) {
    let middle = Math.floor(arrayToSearch.length / 2);
    let currentValue = arrayToSearch[middle];
    if (soughtValue === currentValue) {
        return middle;
    } else if (soughtValue > currentValue) {
        return indexOf(soughtValue, arrayToSearch.slice(middle, arrayToSearch.length));
    } else if (soughtValue < currentValue) {
        return indexOf(soughtValue, arrayToSearch.slice(0, middle));
    }
}

let x = indexOf("Sarah", ["Jennifer", "Sarah", "David", "Jon"]);
console.log(x); // expecting 1

然而正如我之前所说,堆栈溢出。

我仔细阅读了我的教科书对二分查找的解释,然后我查阅了哈佛Intro CS关于算法的讲座。我很自信我理解它的想法,我相当自信的JavaScript正在做我期望的事情。我理解堆栈溢出的概念以及递归算法可能触发的原因。

然而,一遍又一遍地重读我的代码,我无法发现我搞砸了这一点并犯了一个逻辑错误。

如果有人能够启发我,我会非常感激,因为我在这里已经完全耗尽了自己的心理资源而且空洞。

1 个答案:

答案 0 :(得分:0)

根据我上面的评论,这是一个完整的工作示例。重大变化:

  1. 我没有对数组进行切片,而是使用startend索引传递原始数组。这是确保返回的索引是原始数组索引的一种方法。
  2. 当我递归时,我确保中间元素不包含在递归调用中。
  3. 当我们搜索的数组部分为空时,我有一个返回-1的基本案例(就像大多数内置indexOf实现的行为一样)。
  4. 当然,根据我的第一条评论,我开始使用排序数组,因为二进制搜索仅适用于已排序的输入。

    &#13;
    &#13;
    function indexOf(soughtValue, arrayToSearch, start=0, end=(arrayToSearch.length-1)) {
        // base case for an empty array or otherwise failing to find the element
        if (start > end) {
            return -1;
        }
    
        let middle = start + Math.floor((end - start) / 2);
        let currentValue = arrayToSearch[middle];
    
        if (soughtValue === currentValue) {
            return middle;
        } else if (soughtValue > currentValue) {
            return indexOf(soughtValue, arrayToSearch, middle + 1, end);
        } else if (soughtValue < currentValue) {
            return indexOf(soughtValue, arrayToSearch, start, middle - 1);
        }
    }
    
    let input = ["David", "Jennifer", "Jon", "Sarah"];
    console.log(indexOf("David", input)); // 0
    console.log(indexOf("Jennifer", input)); // 1
    console.log(indexOf("Jon", input)); // 2
    console.log(indexOf("Sarah", input)); // 3
    console.log(indexOf("NOT THERE", input)); // -1
    &#13;
    &#13;
    &#13;

    <强>更新

    仅供参考,这样的函数可以很容易地迭代编写而不是递归。在这种情况下,我认为我更喜欢迭代版本:

    &#13;
    &#13;
    function indexOf(soughtValue, arrayToSearch) {
        let start = 0;
        let end = arrayToSearch.length - 1;
    
        while (start <= end) {
            let middle = start + Math.floor((end-start) / 2);
            let currentValue = arrayToSearch[middle];
    
            if (soughtValue > currentValue) {
                start = middle + 1;
            } else if (soughtValue < currentValue) {
                end = middle - 1;
            } else {
                return middle;
            }
        }
    
        // not found
        return -1;
    }
    
    let input = ["David", "Jennifer", "Jon", "Sarah"];
    console.log(indexOf("David", input)); // 0
    console.log(indexOf("Jennifer", input)); // 1
    console.log(indexOf("Jon", input)); // 2
    console.log(indexOf("Sarah", input)); // 3
    console.log(indexOf("NOT THERE", input)); // -1
    &#13;
    &#13;
    &#13;