zoukankan      html  css  js  c++  java
  • 一个JavaScript递归引出的问题

    递归引出问题

     最近在看一本JS方面的书,名字叫《JavaScript语言精粹(修订版)》。在看到递归这一节的时候,有一段代码让我想了大概几分钟才想明白是怎么回事,代码如下:

            var haoni = function(disc, src, aux, dst){
                if(disc > 0){
                    haoni(disc - 1, src, dst, aux);
    
                    document.writeln('Move disc ' + disc + ' from ' + src + ' to ' + dst + '<br/>');
    
                    haoni(disc -1, aux, src, dst);
                }
            };
    
            haoni(3, 'Src', 'Aux', 'Dst');
    View Code

    这是一个有关“汉诺塔”的js实现代码。我主要是看过输出的结果有点不明白。输出如下:

    Move disc 1 from Src to Dst
    Move disc 2 from Src to Aux
    Move disc 1 from Dst to Aux
    Move disc 3 from Src to Dst
    Move disc 1 from Aux to Src
    Move disc 2 from Aux to Dst
    Move disc 1 from Src to Dst

    或许这样的输出还看不出什么。如果你在每句代码下添加一句打印的代码,结果就很让人迷糊了,如:

            var haoni = function(disc, src, aux, dst){
                document.write('111<br/>');
                if(disc > 0){
                    document.write('222<br/>');
                    haoni(disc - 1, src, dst, aux);
                    document.write('333<br/>');
    
                    document.writeln('Move disc ' + disc + ' from ' + src + ' to ' + dst + '<br/>');
    
                    document.write('444<br/>');
                    haoni(disc -1, aux, src, dst);
    
                    document.write('555<br/>');
                }
                document.write('666<br/>  ');
            };
    
            haoni(3, 'Src', 'Aux', 'Dst');
    View Code

    结果如下:

    111
    222
    111
    222
    111
    222
    111
    666
    333
    Move disc 1 from Src to Dst
    444
    111
    666
    555
    666
    333
    Move disc 2 from Src to Aux
    444
    111
    222
    111
    666
    333
    Move disc 1 from Dst to Aux
    444
    111
    666
    555
    666
    555
    666
    333
    Move disc 3 from Src to Dst
    444
    111
    222
    111
    222
    111
    666
    333
    Move disc 1 from Aux to Src
    444
    111
    666
    555
    666
    333
    Move disc 2 from Aux to Dst
    444
    111
    222
    111
    666
    333
    Move disc 1 from Src to Dst
    444
    111
    666
    555
    666
    555
    666
    555
    666
    View Code

    如果你仔细看下打印的结果,你会发现结果很有意思,这里可以自己发现哦-_-!。

    思考问题-查找资料

     细心的人应该会看出上面的疑问。为什么会这样:

    666
    333   //为什么666之后会是333
    Move disc 1 from Src to Dst

    这里就要说点其他的了。

    JavaScript中有一个重要的东西叫“执行环境”。执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为。而每个执行环境都有一个和他有关的变量对象,环境中定义的所有变量和函数都保存在这个对象中。每个函数都有自己的执行环境。当执行流进入一个函数的时候。函数的执行环境会被推入一个环境栈中。而函数执行之后栈会将他的执行环境弹出,把控制权返回给之前的执行环境。

    这段话摘自:《JavaScript高级程序设计》。所以上面的问题就有了解答。

    从一个例子解答问题

    我们先来看一个小例子:

            (function(num){
                if(num > 1){
                    console.log('11');
                    arguments.callee(num-1);
                    console.log('22');
                }
            }(3));

    结果:

    11
    11
    22
    22

    根据上面资料的介绍,这个结果也就很好理解了。当第一次执行的时候num是3,进入if判断打印‘11’。然后调用自身,这个时候函数(这里叫A)会进入另外一个函数(这里叫B)而新的执行环境也会进来(虽然另外一个函数还是自身)。结果进入到新的函数之后再次if判断,结果符合条件就再次打印‘11’,然后执行环境再次被改变(这里叫C)。在新的执行环境内发现if不在满足,退出当前的执行环境(这里是从C退出),把控制权交给之前的执行环境(这里交给的是B不是A,然后打印‘22‘),而B在这时也不在满足条件就在交给最初的A,然后A继续接下来的执行打印’22‘。

    因此

    这样上面的结果也就比较好理解了,只是函数里面有两个递归,当第一个递归把控制权交回到最开始的时候是第二个递归的开始,所以就会看到打印的结果跳来跳去,所以使用递归的时候一定要注意。

  • 相关阅读:
    Codeforces 1255B Fridge Lockers
    Codeforces 1255A Changing Volume
    Codeforces 1255A Changing Volume
    leetcode 112. 路径总和
    leetcode 129. 求根到叶子节点数字之和
    leetcode 404. 左叶子之和
    leetcode 104. 二叉树的最大深度
    leetcode 235. 二叉搜索树的最近公共祖先
    450. Delete Node in a BST
    树的c++实现--建立一棵树
  • 原文地址:https://www.cnblogs.com/Dn9x/p/3517625.html
Copyright © 2011-2022 走看看