【问题标题】:undefined is returned from function从函数返回未定义
【发布时间】:2019-12-03 00:05:41
【问题描述】:

我正在研究二进制搜索,这是我想出的第一件事:

 function letsGoBinary(firstArray,array,search){
    const middle = Math.floor(array.length / 2);
    if(search === array[middle]) {
       const rv = firstArray.indexOf(array[middle]);
       return rv
    }else if(search < array[middle]){
       var lowerArray = []
       for(var i = 0; i < middle; i++){
           lowerArray.push(array[i])
       }
       letsGoBinary(firstArray,lowerArray, search)
    }else if(search > array[middle]){
       var forwardArray = []
       for(var i = middle + 1; i < array.length; i++){
           forwardArray.push(array[i]);
       }
       letsGoBinary(firstArray,forwardArray,search)
    }else {
       return -1
    } 
 }

console.log(letsGoBinary([1,4,7,14,16],[1,4,7,14,16], 4))

如果我在第一个 if 语句 (search === array[middle]) 中添加 console.log() 并记录 rv 它会记录确切的值,并且如果我在 else 语句中记录 not found 也会发生同样的情况,它会记录但在记录时letsGoBinary 其值未定义。我该如何解决?

【问题讨论】:

    标签: javascript function recursion binary-search


    【解决方案1】:

    除了你的问题,请检查 slice 方法是如何工作的,循环不需要获取数组的一部分

    如果你使用,这段代码也有点无意义

    const rv = firstArray.indexOf(array[middle])
    

    那为什么一开始就不用呢

    const rv = firstArray.indexOf(search)
    

    这行代码让你所有的二分搜索都变得毫无意义,因为逐个搜索元素

    有非常简单的解决方案

    function letsGoBinary(array, search){
        let start = 0
        let end = array.length - 1
    
        while (start <= end) {
          const middle = Math.floor((start + end) / 2)   
          if(search === array[middle]) {
             return middle
          } else if (search < array[middle]) {
             end = middle - 1   
          } else {
             start = middle + 1
          }
        }
    
       return -1
     }
    

    【讨论】:

    • 我知道你所说的一切,但是,我真的很想从头开始构建所有东西,因此我的 for 循环和切片都可以线性工作,不管我使用哪一个,我这样做是为了练习. rv 变量只是为了更好地可视化,是的,我试图弄清楚如何返回找到的元素的索引,但是...,还有其他选择吗?
    • @iLiA 是的,我编辑了我的答案,如果你想自己做 - 不要看,我不知道如何将它隐藏在剧透标签中 =) 如果切割数组,你只需制作两个变量beginnig index 和 last index 的搜索和操作
    • 遗憾的是我没有想到这个,但每个人都从某个时候开始。顺便说一句,答案很好,
    • @iLiA,你无法想象我在 17 年前开始我的编程生涯时写了什么样的代码,只是喜欢编码,不需要做得好......一步一步你会得到诀窍
    【解决方案2】:

    在进行递归调用的情况下,需要返回结果。

    return letsGoBinary(firstArray,lowerArray, search);
    

    【讨论】:

    • 为什么?我正在使用 if else 语句,并且只有其中一个会执行,如果它会自动停止执行代码有什么意义
    • return 不仅仅是停止执行。它还设置函数的返回值。如果您不使用它,该函数将不会返回任何值,这由undefined 响应发出信号。
    【解决方案3】:

    在处理递归函数时,您应该具备基本情况,然后当您想要执行递归调用时,您不仅要再次调用该函数,还应该将该函数作为响应返回。 例如,如果搜索编号存在于 lowerArray 中,则意味着您应该返回letsGoBinary(firstArray,lowerArray, search) 作为答案。

    我更新了你的代码,就是这样: 注意:看第 11 和 17 行

    function letsGoBinary(firstArray,array,search){
                const middle = Math.floor(array.length / 2);
                if(search === array[middle]) {
                    const rv = firstArray.indexOf(array[middle]);
                    return rv
                }else if(search < array[middle]){
                    var lowerArray = []
                    for(var i = 0; i < middle; i++){
                        lowerArray.push(array[i])
                    }
                    return letsGoBinary(firstArray,lowerArray, search)
                }else if(search > array[middle]){
                    var forwardArray = []
                    for(var i = middle + 1; i < array.length; i++){
                        forwardArray.push(array[i]);
                    }
                    return letsGoBinary(firstArray,forwardArray,search)
                }else {
                    return -1
                }
            }
    
            console.log(letsGoBinary([1,4,7,14,16],[1,4,7,14,16], 4))

    【讨论】:

    • 对“但您应该将函数作为响应返回”的轻微修正。这应该是“但你应该返回函数调用的结果作为响应”。在 Javascript 中,简单地返回函数是很常见的,但它还有其他用途。
    【解决方案4】:

    这是因为第一次执行 search === array[middle] 后,它完全从letsGoBinary函数返回,因此你必须添加另一个return语句,请找到下面的代码sn-p:

    function letsGoBinary(firstArray,array,search){
    const middle = Math.floor(array.length / 2);
    if(search === array[middle]) {
       const rv = firstArray.indexOf(array[middle]);
       return rv
    }else if(search < array[middle]){
       var lowerArray = []
       for(var i = 0; i < middle; i++){
           lowerArray.push(array[i])
       }
       return letsGoBinary(firstArray,lowerArray, search)
    }else if(search > array[middle]){
       var forwardArray = []
       for(var i = middle + 1; i < array.length; i++){
           forwardArray.push(array[i]);
           }
           return letsGoBinary(firstArray,forwardArray,search)
        }else {
           return -1
        } 
     }
    
    console.log(letsGoBinary([1,4,7,14,16],[1,4,7,14,16], 4))
    

    【讨论】:

      【解决方案5】:

      Dmitry Reutov 的回答很棒。如果您更喜欢递归版本,这是一种类似的方法,但使用递归而不是 while 循环:

      const letsGoBinary = (
        sortedArray, 
        value, 
        start = 0, 
        end = sortedArray .length - 1, 
        middle = Math.floor ((end + start) / 2)
      ) =>
        start > end
          ? -1
        : sortedArray [middle] == value
          ? middle
        : sortedArray [middle] < value
          ? letsGoBinary (sortedArray, value, middle + 1, end)
        : letsGoBinary (sortedArray, value, start, middle - 1)
      
      console .log (
        letsGoBinary ([1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233], 34)
      )

      这两种解决方案都只使用一个数组,依靠startendmiddle 索引来跟踪当前搜索位置。

      此版本在第一次调用时默认startend,然后在后续搜索中传递它们。 middle 在每次调用时计算为startend 之间最接近的整数中点。

      对于本例,第一个调用使用012 中的startend 使middle 6,我们正在测试的值将是sortedArray[6],即@ 987654338@。这小于34的搜索值,所以我们再次调用712,这使得middle变成9和测试值55。这大于34,所以我们调用78middle7,测试值21。那个值小于我们的值,我们再调用一次startend 两者都是8,这给了我们8middle34 的测试值。因为这等于我们的值,所以我们返回8。如果我们错过了——也许我们正在搜索35——然后我们将再次调用9start8end,并返回-1,因为start >end。或者,如果我们一直在搜索 33,我们将得到 8start7end,具有相同的 -1 结果。

      【讨论】:

        猜你喜欢
        • 2012-01-15
        • 1970-01-01
        • 2012-12-14
        • 1970-01-01
        • 1970-01-01
        • 2018-02-04
        • 1970-01-01
        • 1970-01-01
        • 2020-10-22
        相关资源
        最近更新 更多