return语句如何在JavaScript中的递归函数中返回值?

时间:2018-01-19 11:37:56

标签: javascript recursion return

有人可以解释一下这个递归函数是如何工作的。我无法理解如何在调用堆栈中返回值。你能解释一下代表执行环境的图形吗?如果你可以解释Udemy课程中解释的方式,那就更好了 - 理解奇怪的部分。

function findSolution(target) {

    function find(start, history) {
        if (start == target)
            return history;
        else if (start > target)
           return null;
        else
            return find(start + 5, "(" + history + " + 5) ") || find(start * 3, "(" + history + " * 3) ");
    }

return find(1, "1");
}
console.log(findSolution(13));

3 个答案:

答案 0 :(得分:1)

你所拥有的是一个具有两个退出条件的递归函数,一个用于找到的结果,其中start和target值相等,这将返回历史记录,一个起始值大于目标值,返回{ {1}}找不到结果。

递归machanis是在两个方向上分支函数的调用,一个是添加fice,另一个是将值乘以三。

分支以logical OR ||进行,这意味着如果第一个分支返回truthy结果,则会获得此结果,而从不调用另一个分支。如果第一个分支返回nullfalsy值,则调用第二个分支。

你最终得到的是一棵带树枝和测试的树。

null

这意味着,在第一次通话时,它以1开头,如有必要则转到2和3,依此类推。

要想出一个主意,你可以在console.log中添加一个关卡变量,并观察每个级别的内容。

      1          level 0
    /   \
  2       5      level 1
 / \     / \
3   4   6   7    level 2

level, start, history                         action
--------------------------------------------  ----------------
0 1 1                                         check next level
    1 6 (1 + 5)                               check next level
        2 11 ((1 + 5)  + 5)                   check next level
            3 16 (((1 + 5)  + 5)  + 5)        null
            3 33 (((1 + 5)  + 5)  * 3)        null
        2 18 ((1 + 5)  * 3)                   null
    1 3 (1 * 3)                               check next level
        2 8 ((1 * 3)  + 5)                    check next level
            3 13 (((1 * 3)  + 5)  + 5)        found

(((1 * 3)  + 5)  + 5)                         result
function findSolution(target) {

    function find(start, history, level) {
        level = level || 0;
        console.log(level, start, history);
        if (start == target) return history;            // exit condition 1 (found)
        if (start > target) return null;                // exit condition 2 (not found)
        return find(start + 5, "(" + history + " + 5) ", level + 1) ||
               find(start * 3, "(" + history + " * 3) ", level + 1);
    }

    return find(1, "1");
}
console.log(findSolution(13));

答案 1 :(得分:0)

尝试绘制了几个执行案例供您参考。我想这里唯一棘手的部分是行return find(start + 5, "(" + history + " + 5) ") || find(start * 3, "(" + history + " * 3) ");

可能不明显的是||被称为short circuit or in JS。这意味着,如果我们var x = a || b b仅在a不真实的情况下进行评估。

在您的问题的上下文中,提到的行基本上是说“尝试沿着添加5的路径,并且仅在此失败的情况下(即,返回null)尝试沿着乘以3的路径前进。

这里的递归函数find基本上有三种情况:

  1. start == target是真的,这意味着我们已经通过解决方案到达了递归的末尾。这将返回历史记录字符串
  2. start > target为真,这意味着我们已超越目标,返回null表示此路径未导致解决方案
  3. 这两种情况都不是有效的。 Try going down the path of adding 5。如果这不起作用(我们返回null),try going down the path of multiplying 3
  4. 示例案例:

    findSolution(0) //target=0
        find(1, "1") //This goes to Case 3
            find(1+5,"(1 + 5)") || find(1*3,"(1 * 3)")
                find(1+5,"(1 + 5)") // This is a Case 2, returns null, try multiplying by 3 now
                find(1*3,"(1 * 3)") // This is Case 2 again, returns null
            null || null //Both paths lead to null, stop recursing, return null
        null
    null
    
    
    
    findSolution(1) //target=1
        find(1,"1") // This leads to the case 1. Return the history string
        "1"
    "1"
    
    findSolution(3) //target = 3
        find(1,"1") //This leads to case 3
            find(1+3,"(1 + 5)") || find(1*3,"(1 * 3)")
                find(1+5,"(1 + 5)") // This is a Case 2, returns null, try multiplying by 3 now
                find(1*3, "(1 * 3)") // This is a case 1, return History string, recursion ends
            null || "(1 * 3)"
        "(1 * 3)"
    "(1 * 3)"
    
    findSolution(8) //target=8
        find(1,"1") //This leads to case 3
            find(1+5,"(1 + 5)") || find(1*3,"(1 * 3)") // Evaluate lhs first
                find(1+5,"(1 + 5)") // This is a case 3 scenario again
                    find(6 + 5,"((1 + 5) + 5)") || find(6 * 3, "((1 + 5) * 3)")
                        find(6 + 5,"((1 + 5) + 5)") // Case 2, returns null
                        find(6 * 3, "((1 + 5) * 3)") // Case 2, returns null
                    null || null //Going down the add 5 path failed here, try multiplying 3
                find(1*3,"(1 * 3)") // This is a case 3
                    find(3 + 5, "((1*3)+5)") || find(3 * 3, "((1 * 3) * 3")
                        find(8,"((1*3)+5)")  // This is case 1, recursion ends, return history
                        "((1*3)+5)"
                    "((1*3)+5)" || find(..) //LHS evaluated to true, no need to do rhs
                "((1*3)+5)"
            "((1*3)+5)"
        "((1*3)+5)"
    "((1*3)+5)"
    

答案 2 :(得分:-1)

简单来说,

递归函数是一个在执行过程中调用自身的函数。这使函数能够多次重复,输出结果和每次迭代的结束。

递归函数在计算机科学中很常见,因为它们允许程序员使用最少量的代码编写高效的程序。

缺点是如果写得不正确,它们会导致无限循环和其他意外结果。

递归函数开发和执行是基于编程的复杂性和本质的变体。如果我们只是假设要为任何高达100的值递归递增值,那么可能它实际上很容易实现,但在真实的编程环境中,我们面临着许多复杂的问题。

function increment(start){    
    if(start < 100){
        start++;
        increment(start);     
        console.log(start);
    }else{
        console.log("value reached to 100");
    }
}
increment(0);

在这段代码中,我使用了递增函数,递增1。

increment(0);

这是函数调用,我可以将初始值指定为0,它将在函数中以1开始递增。

if(start < 100){
    start++;
    increment(start);     
    console.log(start);
}else{
    console.log("value reached to 100");
}

我把比较限制高达100,所以我的函数调用了101次。一旦达到极限并且(开始&lt; 100)条件为false,它将显示else代码消息。

如果我没有给出100的限制,那么它进入无限循环并且javascript调用堆栈最大大小超过错误或者浏览器可能进入无限循环。

希望我的解释可以帮到你。请查看网站,这对您理解递归和递归方法肯定有帮助。

http://pages.cs.wisc.edu/~calvin/cs110/RECURSION.html

https://javascript.info/recursion