【问题标题】:Recursive functions in Javascript and depth-trackingJavascript 中的递归函数和深度跟踪
【发布时间】:2012-03-12 05:39:24
【问题描述】:

我正在用 JS 编写一个递归函数并且遇到了一些麻烦。让我们从这个非常基本的功能开始:

function traverse(thing)
{
    if (typeof traverse.depth == 'undefined')
        traverse.depth = 1;
    else
        traverse.depth ++;

    if (thing.child)
        traverse(thing.child);
}

所以这工作正常,depth 充当某种静态变量,但问题是在像 C 这样具有适当静态变量的语言中,当您退出函数时,这个变量会(表面上)减少,所以它是一个真正的深度。如果我有三个包含三个盒子的盒子,每个盒子都包含三个盒子,等等,我们基本上是钻到最深的一个,直到没有孩子,然后回退到兄弟的一个级别,并遍历它的孩子.上面代码的问题是深度不断增加和无限增加,即使从最老的祖先到最小的孩子,TRUTH 深度可能只有 3 或 4。如果每个级别有 80 个兄弟姐妹,那么深度计数器将会飙升。

如何跟踪 JS 递归函数的真实深度?

【问题讨论】:

  • 在最后一个 if 条件之后减少 traverse.depth 怎么样?
  • 首先,您没有显示任何减少traverse.depth 值的代码...
  • 我很抱歉投票以重复关闭 - 我链接到的那个似乎不适用于递归。

标签: javascript recursion


【解决方案1】:

你为什么不直接修改函数签名来获取一个东西和一个索引呢?所以你可以这样称呼它:

function traverse(thing, idx)
    ...
    if (condition)
        traverse(thing.child, ++idx)

【讨论】:

    【解决方案2】:

    不要将计数器附加到函数上。计数器由所有递归调用共享,因此计数器表示函数调用的次数,而不是递归深度。

    depth 作为单独的变量传递时,计数器显示真实深度。

    function traverse(thing, depth)
    {
        if (typeof depth == 'number')
            depth++;
        else
            depth = 1;
    
        if (thing.child)
            traverse(thing, depth);
    }
    

    【讨论】:

    • 这里没有通过引用传递对象,他在函数对象本身附加了一个属性...
    • 还有其他解决方案,但这似乎是最简洁和优雅的。谢谢。
    • @jondavidjohn 你是对的(我读过thing.depth)。不过,解决方案的解释仍然成立。
    • @RobW 毫无疑问,只是想确保我们不会让人们混淆它为什么起作用(并且一开始就不起作用)。
    【解决方案3】:

    另一个(也许更好的)解决方案是利用 JS 函数式编程的优势,并使用高阶函数将所有与深度相关的内务处理保留在主函数之外。例如,考虑以下经典示例:

    function fac(n) {
        if(n < 3)
            return n;
        return n * fac(n - 1);
    }
    

    一旦它比给定值更深,我们希望它打破递归。让我们编写一个包装器:

    function wrapDepth(fn, max) {
        var depth = 0
        return function() {
            if (++depth > max) 
                throw "Too much recursion"
            var out = fn.apply(null, [].slice.call(arguments, 0))
            depth--;
            return out;
        }
    }
    

    创建一个最大深度 = 20 的包装器:

    fac = wrapDepth(fac, 20)
    

    和测试:

     console.log(fac(10)) // 3628800
     console.log(fac(100)) // Too much recursion
    

    请注意,我们没有对主函数 fac 本身进行任何更改,但它的递归深度现在仍在控制之中。

    【讨论】:

      【解决方案4】:

      如果我理解正确,在我看来您想要跟踪递归的深度。但在您的代码中,当您完成 1 级递归时,您永远不会减少深度。

      我尝试了一个简单的代码,我认为这是你想要的,

      DEMO

      HTML:

      <div id="result"></div>
      

      JS:

      var result = document.getElementById('result');
      
      var tmpArray = [1,2,3,4,5,6,7,8];
      
      function depthTest() {
          if (typeof depthTest.depth == 'undefined')
              depthTest.depth = 0;
          else
              depthTest.depth++;
      
          result.innerHTML += depthTest.depth;
      
          if (typeof tmpArray[depthTest.depth] != 'undefined')
              depthTest();
      
          result.innerHTML += depthTest.depth;
          depthTest.depth--;
      }
      
      depthTest(tmpArray);
      

      输出:

      012345678876543210
      

      【讨论】:

        【解决方案5】:

        只需添加:

        traverse.depth--;
        

        就在任何返回语句之前。所以

        if(x === 5)
            return thing;
        

        会变成:

        if(x === 5){
            traverse.depth--;
            return thing;
        }
        

        然后在你关闭函数的}之前添加traverse.depth--;

        【讨论】:

          猜你喜欢
          • 2010-10-25
          • 1970-01-01
          • 1970-01-01
          • 2013-08-02
          • 2019-01-12
          • 2022-10-15
          • 2019-05-13
          • 2017-12-05
          • 1970-01-01
          相关资源
          最近更新 更多