【问题标题】:Can't get javascript recursion [duplicate]无法获得javascript递归[重复]
【发布时间】:2015-07-16 01:24:32
【问题描述】:

这个例子来自 Eloquant javascript,我不知道它是如何工作的。我从其他基本示例中了解了递归的基本原理。谁能向我解释一下这是如何工作的?

在下面的链接中进行了解释。 http://eloquentjavascript.net/03_functions.html

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");
} 

findSolution(24));
//answer
//"(((1 * 3) + 5) * 3)"

【问题讨论】:

标签: javascript recursion


【解决方案1】:
 1. function findSolution(target){
 2.    function find(start, history){
 3.        if (start == target)
 4.            return history;
 5.        else if (start > target) {
 6.            return null;
 7.        }
 8.        else
 9.            return find(start + 5, "(" + history + " + 5)") ||
10.                    find(start * 3, "(" + history + " * 3)")
11.    }
12.    return find(1, "1");
13. } 
14.
15. findSolution(24);

当第 15 行调用函数 findSolution 时,为 target 传入 24。在函数findSolution 内部,定义了另一个函数find。然后在第 12 行使用 find(1, "1") 调用此函数,这将启动递归。在此递归的第一次通过时,将检查递归是否完成。当start 等于target(第3 行)时会发生这种情况,这是之前为findSolution(第15 行)给出的值。在这种情况下,它不会在第一次通过,所以它继续到第 5 行的下一部分。在这一行中,它检查起始值是否超出了目标,如果是,则返回 null。如果不是,则进入第 9 行,递归调用 find 并使用当前的 start 值(第一次通过时为 1)加上 5(所以为 6),如果失败(返回 null [参见第 6 行] ),由于 || 运算符,第 10 行的第二次调用发生。这会尝试start*3,在第一次通过时,这是1*3,或3。这一直持续到它可以添加或乘以start 值。

简而言之,递归通过find 继续进行,而 start 没有到达目标。当 start 值与 target (第 3 行)完全匹配,或者由于第 5 行上的测试(不允许 start + 5start * 3 到超越它。

【讨论】:

    【解决方案2】:

    首先你需要了解内部函数的返回值是如何工作的。

    return func(A) || func(B)
    

    如果 func(A) 不为 null,则返回,否则为 func(B)

    现在我们的目标是 24,起点是find(1, 1)(触发递归函数的外部函数的返回值)

    find(1, 1) 可能有两种可能的输出:

    A: find(6, (1+5))
    or
    B find(3, (1*3))
    

    B 将被搁置,除非我们从 A 获得 null 返回(或到达目标),所以我们继续 A,返回将是:

    Aa: find(11, ((1+5)+5))
    or
    Ab: find(15, ((1+5)*3))
    

    Ab 再次暂停,我们继续 Aa 将返回:

    Aa1: find(16, (((1+5)+5)+5))
    Aa2: find(33, (((1+5)+5)*3))
    

    Aa2 大于目标 (24),因此它永远不会继续。所以我们继续使用 Aa1,它将返回 21,然后是 25,它通过了目标,因此返回 null。所以我们回到 Ab 返回 45 > target。所以A 无论如何都会返回null,现在我们试试B:

    Ba: find(8, ((1*3)+5))
    Bb: find(9, ((1*3)*3))
    

    继续使用 Ba,然后返回:

    Ba1: find(13, (((1*3)+5)+5))
    Ba2: find(24, (((1*3)+5)*3))
    

    我们继续使用 Ba1,它将返回 18,然后是 23,然后是大于目标的 28,因此为空。所以回到Ba2,即24 == target,然后完成计算并返回它的历史,即:

    (((1*3)+5)*3)
    

    jsfiddle DEMO
    您可以看到所有端点的日志(达到 null 时或最终找到匹配时)。

    编辑:
    这是函数的执行方式:

    //instead of find I use f
    findSolution(24) >
    f(1, 1) >
        f(6, (1+5)) >
            f(11, ((1+5)+5)) >
                f(16, (((1+5)+5)+5)) >
                    f(21, ((((1+5)+5)+5)+5)) >
                        f(26, (((((1+5)+5)+5)+5)+5)) > NULL
                        f(63, (((((1+5)+5)+5)+5)*3)) > NULL
                    f(48, ((((1+5)+5)+5)*3)) > NULL
                f(33, (((1+5)+5)*3)) > NULL
            f(18, ((1+5)*3)) >
                f(23, (((1+5)*3)+5)) >
                    f(28, ((((1+5)*3)+5)+5)) > NULL
                    f(69, ((((1+5)*3)+5)*3)) > NULL
                f(54, (((1+5)*3)+5)) > NULL
        f(3, (1*3)) >
            f(8, ((1*3)+5)) >
                f(13, (((1*3)+5)+5)) > 
                    f(18, ((((1*3)+5)+5)+5)) >
                        f(23, (((((1*3)+5)+5)+5)+5)) >
                            f(28, ((((((1*3)+5)+5)+5)+5)+5)) > NULL
                            f(69, ((((((1*3)+5)+5)+5)+5)*3)) > NULL
                        f(54, (((((1*3)+5)+5)+5)*3)) > NULL
                    f(39, ((((1*3)+5)+5)*3)) > NULL
                f(24, (((1*3)+5)*3)) > MATCH
    

    【讨论】:

    • 我认为这应该是一个很好的解释,但我无法让它在我的大脑中发挥作用..我觉得我很愚蠢..我自己..我会继续思考直到我明白..谢谢全部。
    • 我想我明白了。非常感谢 Samurai。 jsdiffle 演示帮助很大。
    • 别担心,添加了执行树,所以它可能会有更多帮助。
    猜你喜欢
    • 2021-10-19
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 2019-06-20
    • 2014-01-15
    • 1970-01-01
    相关资源
    最近更新 更多